1
0
mirror of https://github.com/bdring/Grbl_Esp32.git synced 2025-09-06 20:30:56 +02:00

Try to implement the I2S reset mechanism(not yet works)

I started implementing the reset process for the I2S I/O expander.
It's still not enough.
This commit is contained in:
odaki
2020-04-25 21:16:16 +09:00
parent d1ef2d620b
commit 5f16050312
4 changed files with 290 additions and 151 deletions

View File

@@ -94,11 +94,11 @@
// The 1 bits in LIMIT_MASK set the axes that have limit switches // The 1 bits in LIMIT_MASK set the axes that have limit switches
// For example, if the Y axis has no limit switches but the // For example, if the Y axis has no limit switches but the
// X, Z, A and B axes do, the LIMIT_MASK value would be B11101 // X, Z, A and B axes do, the LIMIT_MASK value would be B11101
#define LIMIT_MASK B0111 //#define LIMIT_MASK B0111
#define X_LIMIT_PIN GPIO_NUM_34 //#define X_LIMIT_PIN GPIO_NUM_34
#define Y_LIMIT_PIN GPIO_NUM_35 //#define Y_LIMIT_PIN GPIO_NUM_35
#define Z_LIMIT_PIN GPIO_NUM_32 //#define Z_LIMIT_PIN GPIO_NUM_32
// Common enable for all steppers. If it is okay to leave // Common enable for all steppers. If it is okay to leave
// your drivers enabled at all times, you can leave // your drivers enabled at all times, you can leave
@@ -125,7 +125,7 @@
// RESET, FEED_HOLD, and CYCLE_START can control GCode execution at // RESET, FEED_HOLD, and CYCLE_START can control GCode execution at
// the push of a button. // the push of a button.
// #define CONTROL_RESET_PIN GPIO_NUM_34 // labeled Reset, needs external pullup #define CONTROL_RESET_PIN GPIO_NUM_34 // labeled Reset, needs external pullup
// #define CONTROL_FEED_HOLD_PIN GPIO_NUM_36 // labeled Hold, needs external pullup // #define CONTROL_FEED_HOLD_PIN GPIO_NUM_36 // labeled Hold, needs external pullup
// #define CONTROL_CYCLE_START_PIN GPIO_NUM_39 // labeled Start, needs external pullup // #define CONTROL_CYCLE_START_PIN GPIO_NUM_39 // labeled Start, needs external pullup
@@ -185,7 +185,7 @@
// The control pins with names that begin with CONTROL_ are // The control pins with names that begin with CONTROL_ are
// ignored by default, to avoid noise problems. To make them // ignored by default, to avoid noise problems. To make them
// work, you must undefine IGNORE_CONTROL_PINS // work, you must undefine IGNORE_CONTROL_PINS
// #undef IGNORE_CONTROL_PINS #undef IGNORE_CONTROL_PINS
// If some of the control pin switches are normally closed // If some of the control pin switches are normally closed
// (the default is normally open), you can invert some of them // (the default is normally open), you can invert some of them

View File

@@ -91,10 +91,16 @@ static atomic_uint_least32_t i2s_port_data = ATOMIC_VAR_INIT(0);
#define I2S_ENTER_CRITICAL() portENTER_CRITICAL(&i2s_spinlock) #define I2S_ENTER_CRITICAL() portENTER_CRITICAL(&i2s_spinlock)
#define I2S_EXIT_CRITICAL() portEXIT_CRITICAL(&i2s_spinlock) #define I2S_EXIT_CRITICAL() portEXIT_CRITICAL(&i2s_spinlock)
static int i2s_ioexpander_initialized = 0;
static volatile uint32_t i2s_ioexpander_pulse_period; static volatile uint32_t i2s_ioexpander_pulse_period;
static uint32_t i2s_ioexpander_remain_time_until_next_pulse; // Time remaining until the next pulse (μsec) static uint32_t i2s_ioexpander_remain_time_until_next_pulse; // Time remaining until the next pulse (μsec)
static volatile i2s_ioexpander_pulse_phase_func_t i2s_ioexpander_pulse_phase_func; static volatile i2s_ioexpander_pulse_phase_func_t i2s_ioexpander_pulse_phase_func;
static uint8_t i2s_ioexpander_ws_pin = -1;
static uint8_t i2s_ioexpander_bck_pin = -1;
static uint8_t i2s_ioexpander_data_pin = -1;
enum i2s_ioexpander_status_t { enum i2s_ioexpander_status_t {
UNKNOWN = 0, UNKNOWN = 0,
RUNNING, RUNNING,
@@ -103,7 +109,248 @@ enum i2s_ioexpander_status_t {
static volatile i2s_ioexpander_status_t i2s_ioexpander_status; static volatile i2s_ioexpander_status_t i2s_ioexpander_status;
// //
// External funtions (without init function) // Internal functions
//
static inline void gpio_matrix_out_check(uint32_t gpio, uint32_t signal_idx, bool out_inv, bool oen_inv) {
//if pin = -1, do not need to configure
if (gpio != -1) {
PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[gpio], PIN_FUNC_GPIO);
gpio_set_direction((gpio_num_t)gpio, (gpio_mode_t)GPIO_MODE_DEF_OUTPUT);
gpio_matrix_out(gpio, signal_idx, out_inv, oen_inv);
}
}
static inline void i2s_reset_fifo_without_lock() {
I2S0.conf.rx_fifo_reset = 1;
I2S0.conf.rx_fifo_reset = 0;
I2S0.conf.tx_fifo_reset = 1;
I2S0.conf.tx_fifo_reset = 0;
}
static void i2s_reset_fifo() {
I2S_ENTER_CRITICAL();
i2s_reset_fifo_without_lock();
I2S_EXIT_CRITICAL();
}
static int i2s_clear_dma_buffers() {
if (!i2s_ioexpander_initialized) {
return -1;
}
for (int buf_idx = 0; buf_idx < DMA_BUF_COUNT; buf_idx++) {
// Clear the DMA buffer
uint32_t port_data = atomic_load(&i2s_port_data);
for (int i = 0; i < DMA_SAMPLE_COUNT; i++) {
dma.buffers[buf_idx][i] = port_data;
}
// Initialize DMA descriptor
dma.desc[buf_idx]->owner = 1;
dma.desc[buf_idx]->eof = 1; // set to 1 will trigger the interrupt
dma.desc[buf_idx]->sosf = 0;
dma.desc[buf_idx]->length = DMA_BUF_LEN;
dma.desc[buf_idx]->size = DMA_BUF_LEN;
dma.desc[buf_idx]->buf = (uint8_t *) dma.buffers[buf_idx];
dma.desc[buf_idx]->offset = 0;
dma.desc[buf_idx]->empty = (uint32_t)((buf_idx < (DMA_BUF_COUNT - 1)) ? (dma.desc[buf_idx + 1]) : dma.desc[0]);
}
return 0;
}
static int i2s_gpio_attach(uint8_t ws, uint8_t bck, uint8_t data) {
// Route the i2s pins to the appropriate GPIO
gpio_matrix_out_check(data, I2S0O_DATA_OUT23_IDX, 0, 0);
gpio_matrix_out_check(bck, I2S0O_BCK_OUT_IDX, 0, 0);
gpio_matrix_out_check(ws, I2S0O_WS_OUT_IDX, 0, 0);
return 0;
}
#define I2S_IOEXP_DETACH_PORT_IDX 0x100
static int i2s_gpio_detach(uint8_t ws, uint8_t bck, uint8_t data) {
// Route the i2s pins to the appropriate GPIO
gpio_matrix_out_check(ws, I2S_IOEXP_DETACH_PORT_IDX, 0, 0);
gpio_matrix_out_check(bck, I2S_IOEXP_DETACH_PORT_IDX, 0, 0);
gpio_matrix_out_check(data, I2S_IOEXP_DETACH_PORT_IDX, 0, 0);
return 0;
}
static int i2s_gpio_shiftout(uint32_t port_data) {
digitalWrite(i2s_ioexpander_ws_pin, LOW);
for (int i = 0; i < 32; i++) {
// XXX do not use raw defines for machine
digitalWrite(i2s_ioexpander_data_pin, !!(port_data & (1 << (31 - i))));
digitalWrite(i2s_ioexpander_bck_pin, HIGH);
digitalWrite(i2s_ioexpander_bck_pin, LOW);
}
digitalWrite(i2s_ioexpander_ws_pin, HIGH); // Latch
return 0;
}
static int i2s_stop() {
I2S_ENTER_CRITICAL();
// Stop FIFO DMA
I2S0.out_link.stop = 1;
// Disconnect DMA from FIFO
I2S0.fifo_conf.dscr_en = 0; //Unset this bit to disable I2S DMA mode. (R/W)
// stop TX module
I2S0.conf.tx_start = 0;
// Force WS to LOW before detach
// This operation prevents unintended WS edge trigger when detach
digitalWrite(i2s_ioexpander_ws_pin, LOW);
// Now, detach GPIO pin from I2S
i2s_gpio_detach(i2s_ioexpander_ws_pin, i2s_ioexpander_bck_pin, i2s_ioexpander_data_pin);
// Force BCK to LOW
// After the TX module is stopped, BCK always seems to be in LOW.
// However, I'm going to do it manually to ensure the BCK's LOW.
digitalWrite(i2s_ioexpander_bck_pin, LOW);
// Transmit recovery data to 74HC595
uint32_t port_data = atomic_load(&i2s_port_data); // current expanded port value
i2s_gpio_shiftout(port_data);
//clear pending interrupt
I2S0.int_clr.val = I2S0.int_st.val;
I2S_EXIT_CRITICAL();
return 0;
}
static int i2s_start() {
if (!i2s_ioexpander_initialized) {
return -1;
}
// Transmit recovery data to 74HC595
uint32_t port_data = atomic_load(&i2s_port_data); // current expanded port value
i2s_gpio_shiftout(port_data);
// Attach I2S to specified GPIO pin
i2s_gpio_attach(i2s_ioexpander_ws_pin, i2s_ioexpander_bck_pin, i2s_ioexpander_data_pin);
//start DMA link
I2S_ENTER_CRITICAL();
i2s_reset_fifo_without_lock();
//reset DMA
I2S0.lc_conf.in_rst = 1;
I2S0.lc_conf.in_rst = 0;
I2S0.lc_conf.out_rst = 1;
I2S0.lc_conf.out_rst = 0;
I2S0.conf.tx_reset = 1;
I2S0.conf.tx_reset = 0;
I2S0.conf.rx_reset = 1;
I2S0.conf.rx_reset = 0;
I2S0.out_link.addr = (uint32_t)dma.desc[0];
// Connect DMA to FIFO
I2S0.fifo_conf.dscr_en = 1; // Set this bit to enable I2S DMA mode. (R/W)
I2S0.int_clr.val = 0xFFFFFFFF;
I2S0.out_link.start = 1;
I2S0.conf.tx_start = 1;
I2S_EXIT_CRITICAL();
return 0;
}
//
// I2S DMA Interrupts handler
//
static void IRAM_ATTR i2s_intr_handler_default(void *arg) {
lldesc_t *finish_desc;
portBASE_TYPE high_priority_task_awoken = pdFALSE;
if (I2S0.int_st.out_eof) {
// Get the descriptor of the last item in the linkedlist
finish_desc = (lldesc_t*) I2S0.out_eof_des_addr;
// If the queue is full it's because we have an underflow,
// more than buf_count isr without new data, remove the front buffer
if (xQueueIsQueueFullFromISR(dma.queue)) {
lldesc_t *front_desc;
// Remove a descriptor from the DMA complete event queue
xQueueReceiveFromISR(dma.queue, &front_desc, &high_priority_task_awoken);
uint32_t port_data = atomic_load(&i2s_port_data);
for (int i = 0; i < DMA_SAMPLE_COUNT; i++) {
front_desc->buf[i] = port_data;
}
front_desc->length = DMA_BUF_LEN;
}
// Send a DMA complete event to the I2S bitstreamer task with finished buffer
xQueueSendFromISR(dma.queue, &finish_desc, &high_priority_task_awoken);
}
if (high_priority_task_awoken == pdTRUE) portYIELD_FROM_ISR();
// clear interrupt
I2S0.int_clr.val = I2S0.int_st.val; //clear pending interrupt
}
//
// I2S bitstream generator task
//
static void IRAM_ATTR i2sIOExpanderTask(void* parameter) {
lldesc_t *dma_desc;
while (1) {
// Wait a DMA complete event from I2S isr
// (Block until a DMA transfer has complete)
xQueueReceive(dma.queue, &dma_desc, portMAX_DELAY);
dma.current = (uint32_t*)(dma_desc->buf);
// It reuses the oldest (just transferred) buffer with the name "current"
// and fills the buffer for later DMA.
if (i2s_ioexpander_status == RUNNING) {
//
// Fillout the buffer for pulse
//
// To avoid buffer overflow, all of the maximum pulse width (normaly about 10us)
// is adjusted to be in a single buffer.
// DMA_SAMPLE_SAFE_COUNT is referred to as the margin value.
// Therefore, if a buffer is close to full and it is time to generate a pulse,
// the generation of the buffer is interrupted (the buffer length is shortened slightly)
// and the pulse generation is postponed until the next buffer is filled.
//
dma.rw_pos = 0;
while (dma.rw_pos < (DMA_SAMPLE_COUNT - SAMPLE_SAFE_COUNT)) {
// no data to read (buffer empty)
if (i2s_ioexpander_remain_time_until_next_pulse < I2S_IOEXP_USEC_PER_PULSE) {
// fillout future DMA buffer (tail of the DMA buffer chains)
if (i2s_ioexpander_pulse_phase_func != NULL) {
(*i2s_ioexpander_pulse_phase_func)(); // should be pushed into buffer max DMA_SAMPLE_SAFE_COUNT
i2s_ioexpander_remain_time_until_next_pulse = i2s_ioexpander_pulse_period;
continue;
}
}
// no pulse data in push buffer (pulse off or idle or callback is not defined)
dma.current[dma.rw_pos++] = atomic_load(&i2s_port_data);
if (i2s_ioexpander_remain_time_until_next_pulse >= I2S_IOEXP_USEC_PER_PULSE) {
i2s_ioexpander_remain_time_until_next_pulse -= I2S_IOEXP_USEC_PER_PULSE;
} else {
i2s_ioexpander_remain_time_until_next_pulse = 0;
}
}
// set filled length to the DMA descriptor
dma_desc->length = dma.rw_pos * I2S_SAMPLE_SIZE;
} else {
// Stepper paused unknown
// (just set current I/O port bits to the buffer)
uint32_t port_data = atomic_load(&i2s_port_data);
for (int i = 0; i < DMA_SAMPLE_COUNT; i++) {
dma.current[i] = port_data;
}
dma.rw_pos = DMA_SAMPLE_COUNT;
dma_desc->length = DMA_BUF_LEN;
}
}
}
//
// External funtions
// //
void IRAM_ATTR i2s_ioexpander_write(uint8_t pin, uint8_t val) { void IRAM_ATTR i2s_ioexpander_write(uint8_t pin, uint8_t val) {
uint32_t bit = 1UL << pin; uint32_t bit = 1UL << pin;
@@ -153,158 +400,27 @@ int i2s_ioexpander_register_pulse_callback(i2s_ioexpander_pulse_phase_func_t fun
return 0; return 0;
} }
// int i2s_ioexpander_reset() {
// Internal functions (and init function) i2s_stop();
// i2s_clear_dma_buffers();
static inline void gpio_matrix_out_check(uint32_t gpio, uint32_t signal_idx, bool out_inv, bool oen_inv) { i2s_start();
//if pin = -1, do not need to configure
if (gpio != -1) {
PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[gpio], PIN_FUNC_GPIO);
gpio_set_direction((gpio_num_t)gpio, (gpio_mode_t)GPIO_MODE_DEF_OUTPUT);
gpio_matrix_out(gpio, signal_idx, out_inv, oen_inv);
}
}
static inline void i2s_reset_fifo_without_lock() {
I2S0.conf.rx_fifo_reset = 1;
I2S0.conf.rx_fifo_reset = 0;
I2S0.conf.tx_fifo_reset = 1;
I2S0.conf.tx_fifo_reset = 0;
}
static void i2s_reset_fifo() {
I2S_ENTER_CRITICAL();
i2s_reset_fifo_without_lock();
I2S_EXIT_CRITICAL();
}
static int i2s_start() {
//start DMA link
I2S_ENTER_CRITICAL();
i2s_reset_fifo_without_lock();
//reset dma
I2S0.lc_conf.in_rst = 1;
I2S0.lc_conf.in_rst = 0;
I2S0.lc_conf.out_rst = 1;
I2S0.lc_conf.out_rst = 0;
I2S0.conf.tx_reset = 1;
I2S0.conf.tx_reset = 0;
I2S0.conf.rx_reset = 1;
I2S0.conf.rx_reset = 0;
I2S0.int_clr.val = 0xFFFFFFFF;
I2S0.out_link.start = 1;
I2S0.conf.tx_start = 1;
I2S_EXIT_CRITICAL();
return 0; return 0;
} }
//
// I2S DMA Interrupts handler
//
static void IRAM_ATTR i2s_intr_handler_default(void *arg) {
lldesc_t *finish_desc;
portBASE_TYPE high_priority_task_awoken = pdFALSE;
if (I2S0.int_st.out_eof) {
// Get the descriptor of the last item in the linkedlist
finish_desc = (lldesc_t*) I2S0.out_eof_des_addr;
// If the queue is full it's because we have an underflow,
// more than buf_count isr without new data, remove the front buffer
if (xQueueIsQueueFullFromISR(dma.queue)) {
uint32_t *finished_buffer;
xQueueReceiveFromISR(dma.queue, &finished_buffer, &high_priority_task_awoken);
// This will avoid any kind of noise that may get introduced due to transmission
// of previous data from tx descriptor on I2S line.
uint32_t port_data = atomic_load(&i2s_port_data);
for (int i = 0; i < DMA_SAMPLE_COUNT; i++) {
finished_buffer[i] = port_data;
}
finish_desc->length = DMA_BUF_LEN;
}
// Send a DMA complete event to the I2S bitstreamer task with finished buffer
xQueueSendFromISR(dma.queue, &finish_desc, &high_priority_task_awoken);
}
if (high_priority_task_awoken == pdTRUE) portYIELD_FROM_ISR();
// clear interrupt
I2S0.int_clr.val = I2S0.int_st.val; //clear pending interrupt
}
//
// I2S bitstream generator task
//
static void IRAM_ATTR i2sIOExpanderTask(void* parameter) {
lldesc_t *dma_desc;
while (1) {
// Wait a DMA complete event from I2S isr
// (Block until a DMA transfer has complete)
xQueueReceive(dma.queue, &dma_desc, portMAX_DELAY);
dma.current = (uint32_t*)(dma_desc->buf);
// It reuses the oldest (just transferred) buffer with the name "current"
// and fills the buffer for later DMA.
if (i2s_ioexpander_status == RUNNING) {
//
// Fillout the buffer for pulse
//
// To avoid buffer overflow, all of the maximum pulse width (normaly about 10us)
// is adjusted to be in a single buffer.
// DMA_SAMPLE_SAFE_COUNT is referred to as the margin value.
// Therefore, if a buffer is close to full and it is time to generate a pulse,
// the generation of the buffer is interrupted (the buffer length is shortened slightly)
// and the pulse generation is postponed until the next buffer is filled.
//
dma.rw_pos = 0;
while (dma.rw_pos < (DMA_SAMPLE_COUNT - SAMPLE_SAFE_COUNT)) {
// no data to read (buffer empty)
if (i2s_ioexpander_remain_time_until_next_pulse < I2S_IOEXP_USEC_PER_PULSE) {
// fillout future DMA buffer (tail of the DMA buffer chains)
if (i2s_ioexpander_pulse_phase_func != NULL) {
(*i2s_ioexpander_pulse_phase_func)(); // should be pushed into buffer max DMA_SAMPLE_SAFE_COUNT
i2s_ioexpander_remain_time_until_next_pulse = i2s_ioexpander_pulse_period;
continue;
}
}
// no pulse data in push buffer (pulse off or idle or callback is not defined)
dma.current[dma.rw_pos++] = atomic_load(&i2s_port_data);
if (i2s_ioexpander_remain_time_until_next_pulse >= I2S_IOEXP_USEC_PER_PULSE) {
i2s_ioexpander_remain_time_until_next_pulse -= I2S_IOEXP_USEC_PER_PULSE;
} else {
i2s_ioexpander_remain_time_until_next_pulse = 0;
}
}
// set filled length to the DMA descriptor
dma_desc->length = dma.rw_pos * I2S_SAMPLE_SIZE;
} else {
// Stepper not started or stopped
// (just set current I/O port bits to the buffer)
uint32_t port_data = atomic_load(&i2s_port_data);
for (int i = 0; i < DMA_SAMPLE_COUNT; i++) {
dma.current[i] = port_data;
}
dma.rw_pos = DMA_SAMPLE_COUNT;
dma_desc->length = DMA_BUF_LEN;
}
}
}
// //
// Initialize funtion (external function) // Initialize funtion (external function)
// //
int i2s_ioexpander_init(i2s_ioexpander_init_t &init_param) { int i2s_ioexpander_init(i2s_ioexpander_init_t &init_param) {
if (i2s_ioexpander_initialized) {
// already initialized
return -1;
}
// To make sure hardware is enabled before any hardware register operations. // To make sure hardware is enabled before any hardware register operations.
periph_module_reset(PERIPH_I2S0_MODULE); periph_module_reset(PERIPH_I2S0_MODULE);
periph_module_enable(PERIPH_I2S0_MODULE); periph_module_enable(PERIPH_I2S0_MODULE);
// Route the i2s pins to the appropriate GPIO // Route the i2s pins to the appropriate GPIO
gpio_matrix_out_check(init_param.data_pin, I2S0O_DATA_OUT23_IDX, 0, 0); i2s_gpio_attach(init_param.ws_pin, init_param.bck_pin, init_param.data_pin);
gpio_matrix_out_check(init_param.bck_pin, I2S0O_BCK_OUT_IDX, 0, 0);
gpio_matrix_out_check(init_param.ws_pin, I2S0O_WS_OUT_IDX, 0, 0);
/** /**
* Each i2s transfer will take * Each i2s transfer will take
@@ -390,9 +506,9 @@ int i2s_ioexpander_init(i2s_ioexpander_init_t &init_param) {
I2S0.conf.rx_reset = 0; I2S0.conf.rx_reset = 0;
//reset dma //reset dma
I2S0.lc_conf.in_rst = 1; I2S0.lc_conf.in_rst = 1; // Set this bit to reset in DMA FSM. (R/W)
I2S0.lc_conf.in_rst = 0; I2S0.lc_conf.in_rst = 0;
I2S0.lc_conf.out_rst = 1; I2S0.lc_conf.out_rst = 1; // Set this bit to reset out DMA FSM. (R/W)
I2S0.lc_conf.out_rst = 0; I2S0.lc_conf.out_rst = 0;
//Enable and configure DMA //Enable and configure DMA
@@ -426,7 +542,7 @@ int i2s_ioexpander_init(i2s_ioexpander_init_t &init_param) {
I2S0.conf.rx_start = 0; I2S0.conf.rx_start = 0;
I2S0.conf.tx_msb_right = 1; // Set this bit to place right-channel data at the MSB in the transmit FIFO. I2S0.conf.tx_msb_right = 1; // Set this bit to place right-channel data at the MSB in the transmit FIFO.
I2S0.conf.tx_right_first = 1; // Set this bit to transmit right-channel data first. I2S0.conf.tx_right_first = 0; // Set this bit to transmit right-channel data first.
I2S0.conf.tx_slave_mod = 0; // Master I2S0.conf.tx_slave_mod = 0; // Master
I2S0.fifo_conf.tx_fifo_mod_force_en = 1; //The bit should always be set to 1. I2S0.fifo_conf.tx_fifo_mod_force_en = 1; //The bit should always be set to 1.
@@ -484,9 +600,16 @@ int i2s_ioexpander_init(i2s_ioexpander_init_t &init_param) {
esp_intr_alloc(ETS_I2S0_INTR_SOURCE, 0, i2s_intr_handler_default, nullptr, &i2s_isr_handle); esp_intr_alloc(ETS_I2S0_INTR_SOURCE, 0, i2s_intr_handler_default, nullptr, &i2s_isr_handle);
esp_intr_enable(i2s_isr_handle); esp_intr_enable(i2s_isr_handle);
// Remember GPIO pin numbers
i2s_ioexpander_ws_pin = init_param.ws_pin;
i2s_ioexpander_bck_pin = init_param.bck_pin;
i2s_ioexpander_data_pin = init_param.data_pin;
i2s_ioexpander_initialized = 1;
// Start the I2S peripheral // Start the I2S peripheral
i2s_start(); i2s_start();
i2s_ioexpander_status = RUNNING; i2s_ioexpander_status = RUNNING;
return 0; return 0;
} }
#endif #endif

View File

@@ -93,7 +93,9 @@ typedef struct {
bck _~_~_~_~_~_~_~_~_~_~_~_~_~_~_~_~_~_~_~_~_~_~_~_~_~_~_~_~_~_~_~_~_~_~... bck _~_~_~_~_~_~_~_~_~_~_~_~_~_~_~_~_~_~_~_~_~_~_~_~_~_~_~_~_~_~_~_~_~_~...
data vutsrqponmlkjihgfedcba9876543210vutsrqponmlkjihgfedcba9876543210____... data vutsrqponmlkjihgfedcba9876543210vutsrqponmlkjihgfedcba9876543210____...
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
^Latches the X bits when ws is switched to High ^
Latches the X bits when ws is switched to High
bit0:Extended GPIO 128, 1: Extended GPIO 129, ..., v: Extended GPIO 159 bit0:Extended GPIO 128, 1: Extended GPIO 129, ..., v: Extended GPIO 159
(data at LEFT Channel will ignored by shift-register IC) (data at LEFT Channel will ignored by shift-register IC)
*/ */
@@ -107,6 +109,8 @@ typedef struct {
/* /*
Initialize I2S and DMA for the stepper bitstreamer Initialize I2S and DMA for the stepper bitstreamer
use I2S0, I2S0 isr, DMA, and FIFO(xQueue). use I2S0, I2S0 isr, DMA, and FIFO(xQueue).
return -1 ... already initialized
*/ */
int i2s_ioexpander_init(i2s_ioexpander_init_t &init_param); int i2s_ioexpander_init(i2s_ioexpander_init_t &init_param);
@@ -166,6 +170,15 @@ int i2s_ioexpander_set_pulse_period(uint32_t period);
*/ */
int i2s_ioexpander_register_pulse_callback(i2s_ioexpander_pulse_phase_func_t func); int i2s_ioexpander_register_pulse_callback(i2s_ioexpander_pulse_phase_func_t func);
/*
Reset i2s I/O expander
- Stop ISR/DMA
- Clear DMA buffer with the current expanded GPIO bits
- Retart ISR/DMA
*/
int i2s_ioexpander_reset();
#endif #endif
/* /*

View File

@@ -449,6 +449,9 @@ void mc_reset() {
} }
#ifdef USE_GANGED_AXES #ifdef USE_GANGED_AXES
ganged_mode = SQUARING_MODE_DUAL; // in case an error occurred during squaring ganged_mode = SQUARING_MODE_DUAL; // in case an error occurred during squaring
#endif
#ifdef USE_I2S_IOEXPANDER
i2s_ioexpander_reset();
#endif #endif
} }
} }