Fix ESP32 i2s stream, add PWM to extended pins (#14592)

This commit is contained in:
Ringel 2019-07-14 17:08:14 +02:00 committed by Scott Lahteine
parent 21e1148d98
commit e139c1d9d9
5 changed files with 100 additions and 33 deletions

View file

@ -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,
pin_to_channel[40] = {};
if (pin_to_channel[pin] == 0) { if (pin_to_channel[pin] == 0) {
ledcAttachPin(pin, cnt_channel); ledcAttachPin(pin, cnt_channel);
ledcSetup(cnt_channel, 490, 8); ledcSetup(cnt_channel, 490, 8);
ledcWrite(cnt_channel, value); ledcWrite(cnt_channel, value);
pin_to_channel[pin] = cnt_channel++; pin_to_channel[pin] = cnt_channel++;
} }
ledcWrite(pin_to_channel[pin], value); ledcWrite(pin_to_channel[pin], value);
return;
}
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

View file

@ -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);
} }

View file

@ -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

View file

@ -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))

View file

@ -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);
} }