Fix ESP32 i2s stream, add PWM to extended pins (#14592)
This commit is contained in:
parent
21e1148d98
commit
e139c1d9d9
5 changed files with 100 additions and 33 deletions
|
@ -23,6 +23,7 @@
|
||||||
#ifdef ARDUINO_ARCH_ESP32
|
#ifdef ARDUINO_ARCH_ESP32
|
||||||
|
|
||||||
#include "HAL.h"
|
#include "HAL.h"
|
||||||
|
#include "HAL_timers_ESP32.h"
|
||||||
#include <rom/rtc.h>
|
#include <rom/rtc.h>
|
||||||
#include <driver/adc.h>
|
#include <driver/adc.h>
|
||||||
#include <esp_adc_cal.h>
|
#include <esp_adc_cal.h>
|
||||||
|
@ -67,6 +68,9 @@ uint16_t HAL_adc_result;
|
||||||
// ------------------------
|
// ------------------------
|
||||||
|
|
||||||
esp_adc_cal_characteristics_t characteristics;
|
esp_adc_cal_characteristics_t characteristics;
|
||||||
|
volatile int numPWMUsed = 0,
|
||||||
|
pwmPins[MAX_PWM_PINS],
|
||||||
|
pwmValues[MAX_PWM_PINS];
|
||||||
|
|
||||||
// ------------------------
|
// ------------------------
|
||||||
// Public functions
|
// Public functions
|
||||||
|
@ -168,25 +172,64 @@ void HAL_adc_init() {
|
||||||
void HAL_adc_start_conversion(uint8_t adc_pin) {
|
void HAL_adc_start_conversion(uint8_t adc_pin) {
|
||||||
uint32_t mv;
|
uint32_t mv;
|
||||||
esp_adc_cal_get_voltage((adc_channel_t)get_channel(adc_pin), &characteristics, &mv);
|
esp_adc_cal_get_voltage((adc_channel_t)get_channel(adc_pin), &characteristics, &mv);
|
||||||
|
HAL_adc_result = mv * 1023.0 / 3300.0;
|
||||||
HAL_adc_result = mv*1023.0/3300.0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void analogWrite(pin_t pin, int value) {
|
void analogWrite(pin_t pin, int value) {
|
||||||
|
// Use ledc hardware for internal pins
|
||||||
if (!PWM_PIN(pin)) return;
|
if (pin < 34) {
|
||||||
|
static int cnt_channel = 1, pin_to_channel[40] = { 0 };
|
||||||
static int cnt_channel = 1,
|
if (pin_to_channel[pin] == 0) {
|
||||||
pin_to_channel[40] = {};
|
ledcAttachPin(pin, cnt_channel);
|
||||||
if (pin_to_channel[pin] == 0) {
|
ledcSetup(cnt_channel, 490, 8);
|
||||||
ledcAttachPin(pin, cnt_channel);
|
ledcWrite(cnt_channel, value);
|
||||||
ledcSetup(cnt_channel, 490, 8);
|
pin_to_channel[pin] = cnt_channel++;
|
||||||
ledcWrite(cnt_channel, value);
|
}
|
||||||
|
ledcWrite(pin_to_channel[pin], value);
|
||||||
pin_to_channel[pin] = cnt_channel++;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ledcWrite(pin_to_channel[pin], value);
|
int idx = -1;
|
||||||
|
|
||||||
|
// Search Pin
|
||||||
|
for (int i = 0; i < numPWMUsed; ++i)
|
||||||
|
if (pwmPins[i] == pin) { idx = i; break; }
|
||||||
|
|
||||||
|
// not found ?
|
||||||
|
if (idx < 0) {
|
||||||
|
// No slots remaining
|
||||||
|
if (numPWMUsed >= MAX_PWM_PINS) return;
|
||||||
|
|
||||||
|
// Take new slot for pin
|
||||||
|
idx = numPWMUsed;
|
||||||
|
pwmPins[idx] = pin;
|
||||||
|
// Start timer on first use
|
||||||
|
if (idx == 0) HAL_timer_start(PWM_TIMER_NUM, PWM_TIMER_FREQUENCY);
|
||||||
|
|
||||||
|
++numPWMUsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use 7bit internal value - add 1 to have 100% high at 255
|
||||||
|
pwmValues[idx] = (value + 1) / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle PWM timer interrupt
|
||||||
|
HAL_PWM_TIMER_ISR() {
|
||||||
|
HAL_timer_isr_prologue(PWM_TIMER_NUM);
|
||||||
|
|
||||||
|
static uint8_t count = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < numPWMUsed; ++i) {
|
||||||
|
if (count == 0) // Start of interval
|
||||||
|
WRITE(pwmPins[i], pwmValues[i] ? HIGH : LOW);
|
||||||
|
else if (pwmValues[i] == count) // End of duration
|
||||||
|
WRITE(pwmPins[i], LOW);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 128 for 7 Bit resolution
|
||||||
|
count = (count + 1) & 0x7F;
|
||||||
|
|
||||||
|
HAL_timer_isr_epilogue(PWM_TIMER_NUM);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // ARDUINO_ARCH_ESP32
|
#endif // ARDUINO_ARCH_ESP32
|
||||||
|
|
|
@ -47,7 +47,7 @@ static timg_dev_t *TG[2] = {&TIMERG0, &TIMERG1};
|
||||||
const tTimerConfig TimerConfig [NUM_HARDWARE_TIMERS] = {
|
const tTimerConfig TimerConfig [NUM_HARDWARE_TIMERS] = {
|
||||||
{ TIMER_GROUP_0, TIMER_0, STEPPER_TIMER_PRESCALE, stepTC_Handler }, // 0 - Stepper
|
{ TIMER_GROUP_0, TIMER_0, STEPPER_TIMER_PRESCALE, stepTC_Handler }, // 0 - Stepper
|
||||||
{ TIMER_GROUP_0, TIMER_1, TEMP_TIMER_PRESCALE, tempTC_Handler }, // 1 - Temperature
|
{ TIMER_GROUP_0, TIMER_1, TEMP_TIMER_PRESCALE, tempTC_Handler }, // 1 - Temperature
|
||||||
{ TIMER_GROUP_1, TIMER_0, 1, nullptr }, // 2
|
{ TIMER_GROUP_1, TIMER_0, PWM_TIMER_PRESCALE, pwmTC_Handler }, // 2 - PWM
|
||||||
{ TIMER_GROUP_1, TIMER_1, 1, nullptr }, // 3
|
{ TIMER_GROUP_1, TIMER_1, 1, nullptr }, // 3
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -55,28 +55,28 @@ const tTimerConfig TimerConfig [NUM_HARDWARE_TIMERS] = {
|
||||||
// Public functions
|
// Public functions
|
||||||
// ------------------------
|
// ------------------------
|
||||||
|
|
||||||
void IRAM_ATTR timer_group0_isr(void *para) {
|
void IRAM_ATTR timer_isr(void *para) {
|
||||||
const int timer_idx = (int)para;
|
const tTimerConfig& timer = TimerConfig[(int)para];
|
||||||
|
|
||||||
// Retrieve the interrupt status and the counter value
|
// Retrieve the interrupt status and the counter value
|
||||||
// from the timer that reported the interrupt
|
// from the timer that reported the interrupt
|
||||||
uint32_t intr_status = TIMERG0.int_st_timers.val;
|
uint32_t intr_status = TG[timer.group]->int_st_timers.val;
|
||||||
TIMERG0.hw_timer[timer_idx].update = 1;
|
TG[timer.group]->hw_timer[timer.idx].update = 1;
|
||||||
|
|
||||||
// Clear the interrupt
|
// Clear the interrupt
|
||||||
if (intr_status & BIT(timer_idx)) {
|
if (intr_status & BIT(timer.idx)) {
|
||||||
switch (timer_idx) {
|
switch (timer.idx) {
|
||||||
case TIMER_0: TIMERG0.int_clr_timers.t0 = 1; break;
|
case TIMER_0: TG[timer.group]->int_clr_timers.t0 = 1; break;
|
||||||
case TIMER_1: TIMERG0.int_clr_timers.t1 = 1; break;
|
case TIMER_1: TG[timer.group]->int_clr_timers.t1 = 1; break;
|
||||||
|
case TIMER_MAX: break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const tTimerConfig timer = TimerConfig[timer_idx];
|
|
||||||
timer.fn();
|
timer.fn();
|
||||||
|
|
||||||
// After the alarm has been triggered
|
// After the alarm has been triggered
|
||||||
// Enable it again so it gets triggered the next time
|
// Enable it again so it gets triggered the next time
|
||||||
TIMERG0.hw_timer[timer_idx].config.alarm_en = TIMER_ALARM_EN;
|
TG[timer.group]->hw_timer[timer.idx].config.alarm_en = TIMER_ALARM_EN;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -106,8 +106,7 @@ void HAL_timer_start(const uint8_t timer_num, uint32_t frequency) {
|
||||||
|
|
||||||
timer_enable_intr(timer.group, timer.idx);
|
timer_enable_intr(timer.group, timer.idx);
|
||||||
|
|
||||||
// TODO need to deal with timer_group1_isr
|
timer_isr_register(timer.group, timer.idx, timer_isr, (void*)timer_num, 0, nullptr);
|
||||||
timer_isr_register(timer.group, timer.idx, timer_group0_isr, (void*)timer.idx, 0, nullptr);
|
|
||||||
|
|
||||||
timer_start(timer.group, timer.idx);
|
timer_start(timer.group, timer.idx);
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,6 +40,7 @@ typedef uint64_t hal_timer_t;
|
||||||
|
|
||||||
#define STEP_TIMER_NUM 0 // index of timer to use for stepper
|
#define STEP_TIMER_NUM 0 // index of timer to use for stepper
|
||||||
#define TEMP_TIMER_NUM 1 // index of timer to use for temperature
|
#define TEMP_TIMER_NUM 1 // index of timer to use for temperature
|
||||||
|
#define PWM_TIMER_NUM 2 // index of timer to use for PWM outputs
|
||||||
#define PULSE_TIMER_NUM STEP_TIMER_NUM
|
#define PULSE_TIMER_NUM STEP_TIMER_NUM
|
||||||
|
|
||||||
#define HAL_TIMER_RATE APB_CLK_FREQ // frequency of timer peripherals
|
#define HAL_TIMER_RATE APB_CLK_FREQ // frequency of timer peripherals
|
||||||
|
@ -59,6 +60,14 @@ typedef uint64_t hal_timer_t;
|
||||||
#define TEMP_TIMER_PRESCALE 1000 // prescaler for setting Temp timer, 72Khz
|
#define TEMP_TIMER_PRESCALE 1000 // prescaler for setting Temp timer, 72Khz
|
||||||
#define TEMP_TIMER_FREQUENCY 1000 // temperature interrupt frequency
|
#define TEMP_TIMER_FREQUENCY 1000 // temperature interrupt frequency
|
||||||
|
|
||||||
|
#define PWM_TIMER_PRESCALE 10
|
||||||
|
#if ENABLED(FAST_PWM_FAN)
|
||||||
|
#define PWM_TIMER_FREQUENCY FAST_PWM_FAN_FREQUENCY
|
||||||
|
#else
|
||||||
|
#define PWM_TIMER_FREQUENCY (50*128) // 50Hz and 7bit resolution
|
||||||
|
#endif
|
||||||
|
#define MAX_PWM_PINS 32 // Number of PWM pin-slots
|
||||||
|
|
||||||
#define PULSE_TIMER_RATE STEPPER_TIMER_RATE // frequency of pulse timer
|
#define PULSE_TIMER_RATE STEPPER_TIMER_RATE // frequency of pulse timer
|
||||||
#define PULSE_TIMER_PRESCALE STEPPER_TIMER_PRESCALE
|
#define PULSE_TIMER_PRESCALE STEPPER_TIMER_PRESCALE
|
||||||
#define PULSE_TIMER_TICKS_PER_US STEPPER_TIMER_TICKS_PER_US
|
#define PULSE_TIMER_TICKS_PER_US STEPPER_TIMER_TICKS_PER_US
|
||||||
|
@ -72,10 +81,11 @@ typedef uint64_t hal_timer_t;
|
||||||
|
|
||||||
#define HAL_TEMP_TIMER_ISR() extern "C" void tempTC_Handler(void)
|
#define HAL_TEMP_TIMER_ISR() extern "C" void tempTC_Handler(void)
|
||||||
#define HAL_STEP_TIMER_ISR() extern "C" void stepTC_Handler(void)
|
#define HAL_STEP_TIMER_ISR() extern "C" void stepTC_Handler(void)
|
||||||
|
#define HAL_PWM_TIMER_ISR() extern "C" void pwmTC_Handler(void)
|
||||||
|
|
||||||
extern "C" void tempTC_Handler(void);
|
extern "C" void tempTC_Handler(void);
|
||||||
extern "C" void stepTC_Handler(void);
|
extern "C" void stepTC_Handler(void);
|
||||||
|
extern "C" void pwmTC_Handler(void);
|
||||||
|
|
||||||
// ------------------------
|
// ------------------------
|
||||||
// Types
|
// Types
|
||||||
|
|
|
@ -66,7 +66,7 @@
|
||||||
#define extDigitalWrite(IO,V) digitalWrite(IO,V)
|
#define extDigitalWrite(IO,V) digitalWrite(IO,V)
|
||||||
|
|
||||||
// PWM outputs
|
// PWM outputs
|
||||||
#define PWM_PIN(P) (P < 34) // NOTE Pins >= 34 are input only on ESP32, so they can't be used for output.
|
#define PWM_PIN(P) (P < 34 || P > 127) // NOTE Pins >= 34 are input only on ESP32, so they can't be used for output.
|
||||||
|
|
||||||
// Toggle pin value
|
// Toggle pin value
|
||||||
#define TOGGLE(IO) WRITE(IO, !READ(IO))
|
#define TOGGLE(IO) WRITE(IO, !READ(IO))
|
||||||
|
|
|
@ -56,7 +56,7 @@ static i2s_dev_t* I2S[I2S_NUM_MAX] = {&I2S0, &I2S1};
|
||||||
static i2s_dma_t dma;
|
static i2s_dma_t dma;
|
||||||
|
|
||||||
// output value
|
// output value
|
||||||
uint32_t i2s_port_data;
|
uint32_t i2s_port_data = 0;
|
||||||
|
|
||||||
#define I2S_ENTER_CRITICAL() portENTER_CRITICAL(&i2s_spinlock[i2s_num])
|
#define I2S_ENTER_CRITICAL() portENTER_CRITICAL(&i2s_spinlock[i2s_num])
|
||||||
#define I2S_EXIT_CRITICAL() portEXIT_CRITICAL(&i2s_spinlock[i2s_num])
|
#define I2S_EXIT_CRITICAL() portEXIT_CRITICAL(&i2s_spinlock[i2s_num])
|
||||||
|
@ -140,13 +140,13 @@ static void IRAM_ATTR i2s_intr_handler_default(void *arg) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void stepperTask(void* parameter) {
|
void stepperTask(void* parameter) {
|
||||||
uint32_t i, remaining = 0;
|
uint32_t remaining = 0;
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
xQueueReceive(dma.queue, &dma.current, portMAX_DELAY);
|
xQueueReceive(dma.queue, &dma.current, portMAX_DELAY);
|
||||||
dma.rw_pos = 0;
|
dma.rw_pos = 0;
|
||||||
|
|
||||||
for (i = 0; i < DMA_SAMPLE_COUNT; i++) {
|
while (dma.rw_pos < DMA_SAMPLE_COUNT) {
|
||||||
// Fill with the port data post pulse_phase until the next step
|
// Fill with the port data post pulse_phase until the next step
|
||||||
if (remaining) {
|
if (remaining) {
|
||||||
i2s_push_sample();
|
i2s_push_sample();
|
||||||
|
@ -254,7 +254,13 @@ int i2s_init() {
|
||||||
|
|
||||||
I2S0.fifo_conf.dscr_en = 0;
|
I2S0.fifo_conf.dscr_en = 0;
|
||||||
|
|
||||||
I2S0.conf_chan.tx_chan_mod = 0;
|
I2S0.conf_chan.tx_chan_mod = (
|
||||||
|
#if ENABLED(I2S_STEPPER_SPLIT_STREAM)
|
||||||
|
4
|
||||||
|
#else
|
||||||
|
0
|
||||||
|
#endif
|
||||||
|
);
|
||||||
I2S0.fifo_conf.tx_fifo_mod = 0;
|
I2S0.fifo_conf.tx_fifo_mod = 0;
|
||||||
I2S0.conf.tx_mono = 0;
|
I2S0.conf.tx_mono = 0;
|
||||||
|
|
||||||
|
@ -314,10 +320,19 @@ int i2s_init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void i2s_write(uint8_t pin, uint8_t val) {
|
void i2s_write(uint8_t pin, uint8_t val) {
|
||||||
|
#if ENABLED(I2S_STEPPER_SPLIT_STREAM)
|
||||||
|
if (pin >= 16) {
|
||||||
|
SET_BIT_TO(I2S0.conf_single_data, pin, val);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
SET_BIT_TO(i2s_port_data, pin, val);
|
SET_BIT_TO(i2s_port_data, pin, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t i2s_state(uint8_t pin) {
|
uint8_t i2s_state(uint8_t pin) {
|
||||||
|
#if ENABLED(I2S_STEPPER_SPLIT_STREAM)
|
||||||
|
if (pin >= 16) return TEST(I2S0.conf_single_data, pin);
|
||||||
|
#endif
|
||||||
return TEST(i2s_port_data, pin);
|
return TEST(i2s_port_data, pin);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Reference in a new issue