diff --git a/src/it_handlers.c b/src/it_handlers.c index fe822a1..acca9a3 100644 --- a/src/it_handlers.c +++ b/src/it_handlers.c @@ -152,8 +152,6 @@ void SysTick_Handler(void) { i2cKeepTimeout(); - spi_timeout_handler(); - delay_decrement_counter(); if (it_handlers_inhibit_radiomodem_dcd_led == 0) { diff --git a/src/main.c b/src/main.c index 63fee95..d057ac8 100644 --- a/src/main.c +++ b/src/main.c @@ -1430,6 +1430,8 @@ int main(int argc, char* argv[]){ wx_check_force_i2c_reset(); + max31865_pool(); + #ifdef INTERNAL_WATCHDOG IWDG_ReloadCounter(); #endif diff --git a/system/include/drivers/max31865.h b/system/include/drivers/max31865.h index 1a74b61..30c2a24 100644 --- a/system/include/drivers/max31865.h +++ b/system/include/drivers/max31865.h @@ -20,7 +20,7 @@ typedef enum max31865_qf_t { }max31865_qf_t; void max31865_init(uint8_t rdt_type); -void max31865_start_measurement(void); +void max31865_pool(void); int32_t max31865_get_result(max31865_qf_t * quality_factor); diff --git a/system/include/drivers/spi.h b/system/include/drivers/spi.h index e264703..5f436c7 100644 --- a/system/include/drivers/spi.h +++ b/system/include/drivers/spi.h @@ -1,5 +1,9 @@ /* - * spi_stm32l4x.h + * spi.h + * + * This is a general interface of SPI driver. Please read notes + * in platform specific implementation. Each of them might have + * it's own limitations * * Created on: Sep 22, 2022 * Author: mateusz @@ -10,13 +14,19 @@ #include -#define SPI_OK 0 -#define SPI_BUSY_DIFF_SLAVE 10 -#define SPI_BUSY 11 -#define SPI_TX_DATA_TO_LONG 20 -#define SPI_WRONG_SLAVE_ID 30 -#define SPI_UKNOWN 255 +/** + * Return codes + */ +#define SPI_OK 0 //!< Function has succeeded +#define SPI_BUSY_DIFF_SLAVE 10 //!< Communication has been requested for different slave than what transmission is ongoing for +#define SPI_BUSY 11 //!< SPI bus is currently busy and cannot be used for requested operation +#define SPI_TX_DATA_TO_LONG 20 //!< requested data is too long to fit in internal SPI tx buffer +#define SPI_WRONG_SLAVE_ID 30 //!< unknown SPI slave (missing chip select mapping) +#define SPI_UKNOWN 255 //!< undesignated SPI error +/** + * SPI transfer mode using for initialization + */ typedef enum spi_transfer_mode_t { SPI_MASTER_MOTOROLA, SPI_MASTER_TI, @@ -24,26 +34,39 @@ typedef enum spi_transfer_mode_t { SPI_SLAVE_TI }spi_transfer_mode_t; +/** + * SPI clock mode using for initialization, look at CPOL and CPHA values for each enum values. + */ typedef enum spi_clock_polarity_strobe_t { - CLOCK_NORMAL_FALLING, // CPOL 0, CPHA 1 - CLOCK_NORMAL_RISING, // CPOL 0, CPHA 0 - CLOCK_REVERSED_FALLING, // CPOL 1, CPHA 0 - CLOCK_REVERSED_RISING // CPOL 1, CPHA 1 + CLOCK_NORMAL_FALLING, //!< CPOL 0, CPHA 1 + CLOCK_NORMAL_RISING, //!< CPOL 0, CPHA 0 + CLOCK_REVERSED_FALLING, //!< CPOL 1, CPHA 0 + CLOCK_REVERSED_RISING //!< CPOL 1, CPHA 1 }spi_clock_polarity_strobe_t; #define SPI_ENDIAN_LSB 0 #define SPI_ENDIAN_MSB 1 +#define SPI_TX_FROM_INTERNAL 1 +#define SPI_TX_FROM_EXTERNAL 2 + +#define SPI_USE_INTERNAL_RX_BUF 0 + +/** + * Current SPI reception state + */ typedef enum spi_rx_state_t { - SPI_RX_IDLE, // SPI is configured and ready for operation - SPI_RX_RXING, // SPI is currently receiving - SPI_RX_DONE, // Reception is done - SPI_RX_WAITING_FOR_RX, // SPI is currently transmitting and reception is queued - SPI_RX_ERROR_OVERRUN, // Overrun had been detected and reception was terminated + SPI_RX_IDLE, //!< SPI is configured and ready for operation + SPI_RX_RXING, //!< SPI is currently receiving + SPI_RX_DONE, //!< Reception is done + SPI_RX_WAITING_FOR_RX, //!< SPI is currently transmitting and reception is queued + SPI_RX_ERROR_OVERRUN, //!< Overrun had been detected and reception was terminated SPI_RX_ERROR_MODF, - SPI_RX_ERROR_TIMEOUT // Timeout has been detected }spi_rx_state_t; +/** + * Current SPI transmission state + */ typedef enum spi_tx_state_t { SPI_TX_IDLE, SPI_TX_TXING, @@ -51,21 +74,30 @@ typedef enum spi_tx_state_t { SPI_TX_ERROR_MODF }spi_tx_state_t; -#define SPI_TIMEOUT_MSEC 100 - +//! This function initializes SPI bus to work as full duplex two-wire connection, w/o DMA data flow uint8_t spi_init_full_duplex_pio(spi_transfer_mode_t mode, spi_clock_polarity_strobe_t strobe, int speed, int endianess); -uint8_t spi_rx_data(uint32_t slave_id, uint8_t * rx_buffer, uint16_t ln_to_rx); -uint8_t spi_tx_data(uint32_t slave_id, uint8_t * tx_buffer, uint16_t ln_to_tx); -uint8_t spi_rx_tx_data(uint32_t slave_id, uint8_t * rx_buffer, uint8_t * tx_buffer, uint16_t ln_to_rx, uint16_t ln_to_tx); + +//! Sends data asynchronously to selected SPI slave, discards anything what will come in over MISO line +uint8_t spi_tx_data(uint32_t slave_id, uint8_t tx_from_internal, uint8_t * tx_buffer, uint16_t ln_to_tx); + +//! Sends data synchronously to selected slave and after that receives data from it. Everything received before TX is finish is discarded. +uint8_t spi_rx_tx_data(uint32_t slave_id, uint8_t tx_from_internal, uint8_t * rx_buffer, uint8_t * tx_buffer, uint16_t ln_to_rx, uint16_t ln_to_tx); + +//! Returns pointer to receive buffer and if reception is done resets RX state back to idle. uint8_t * spi_get_rx_data(void); +//! Blocking wait until both RX and TX is done uint8_t spi_wait_for_comms_done(void); + +//! Resets all errors and reverts state back to IDLE void spi_reset_errors(void); -void spi_irq_handler(void); -void spi_timeout_handler(void); +spi_rx_state_t spi_get_rx_state(void); +spi_tx_state_t spi_get_tx_state(void); -void spi_enable(uint8_t cs_assert); -void spi_disable(uint8_t immediately); +//! Returns an ID of current SPI slave or zero if SPI is idle +uint32_t spi_get_current_slave(void); + +void spi_irq_handler(void); #endif /* INCLUDE_DRIVERS_SPI_H_ */ diff --git a/system/src/drivers/l4/spi_stm32l4xx.c b/system/src/drivers/l4/spi_stm32l4xx.c index 68df47a..7a13328 100644 --- a/system/src/drivers/l4/spi_stm32l4xx.c +++ b/system/src/drivers/l4/spi_stm32l4xx.c @@ -1,6 +1,9 @@ /* * spi_stm32l4xx.c * + * This module consist an implementation of SPI driver for STM32L4xx micro, but with some + * limitations over what this micro actually supports. + * * Created on: Sep 22, 2022 * Author: mateusz */ @@ -81,11 +84,6 @@ uint8_t * spi_tx_buffer_ptr; */ uint8_t spi_garbage; -/** - * Timestamp when receiving has been initiated - */ -uint32_t spi_timestamp_rx_start; - /** * How many bytes has been discarded into garbage storage */ @@ -93,6 +91,65 @@ uint8_t spi_garbage_counter = 0; EVAL_SLAVE_ARR +static void spi_enable(uint8_t cs_assert) { + + // delay between asserting chip select and starting SPI + volatile int delay = 0; + + SPI2->CR2 |= SPI_CR2_ERRIE; + SPI2->CR2 |= SPI_CR2_RXNEIE; + SPI2->CR2 |= SPI_CR2_TXEIE; + + if (cs_assert != 0) { + LL_GPIO_ResetOutputPin((GPIO_TypeDef *)spi_slaves_cfg[spi_current_slave - 1][1], spi_slaves_cfg[spi_current_slave - 1][2]); + + // delay required by CS to SCLK Setup (MAX31865) + for (delay = 0; delay < SPI_CS_TO_SCLK_SETUP_DELAY; delay++); + } + + LL_SPI_Enable(SPI2); +} + +/** + * This function will disable SPI and close bus communication, optionally + * it can wait until the peripheral will be released + */ +static void spi_disable(uint8_t immediately) { + + if (immediately == 0) { + while ((SPI2->SR & SPI_SR_BSY) != 0); + + LL_GPIO_SetOutputPin((GPIO_TypeDef *)spi_slaves_cfg[spi_current_slave - 1][1], spi_slaves_cfg[spi_current_slave - 1][2]); + + LL_SPI_Disable(SPI2); + + // disable all interrupts + SPI2->CR2 &= (0xFFFFFFFF ^ SPI_CR2_ERRIE); + SPI2->CR2 &= (0xFFFFFFFF ^ SPI_CR2_RXNEIE); + SPI2->CR2 &= (0xFFFFFFFF ^ SPI_CR2_TXEIE); + + if ((SPI2->SR & SPI_SR_RXNE) != 0) { + // clear RX fifo queue + do { + spi_garbage_counter++; + + spi_garbage = SPI2->DR & 0xFF; + } while ((SPI2->SR & SPI_SR_RXNE) != 0); + } + } + else { + LL_GPIO_SetOutputPin((GPIO_TypeDef *)spi_slaves_cfg[spi_current_slave - 1][1], spi_slaves_cfg[spi_current_slave - 1][2]); + + // disable all interrupts + SPI2->CR2 &= (0xFFFFFFFF ^ SPI_CR2_ERRIE); + SPI2->CR2 &= (0xFFFFFFFF ^ SPI_CR2_RXNEIE); + SPI2->CR2 &= (0xFFFFFFFF ^ SPI_CR2_TXEIE); + + LL_SPI_Disable(SPI2); + } + +} + uint8_t spi_init_full_duplex_pio(spi_transfer_mode_t mode, spi_clock_polarity_strobe_t strobe, int speed, int endianess) { LL_GPIO_InitTypeDef GPIO_InitTypeDef; @@ -290,7 +347,7 @@ uint8_t spi_rx_data(uint32_t slave_id, uint8_t * rx_buffer, uint16_t ln_to_rx) { /** * Initiate tx only transaction. Data will be sent to chosen slave, any receive data will be discarded */ -uint8_t spi_tx_data(uint32_t slave_id, uint8_t * tx_buffer, uint16_t ln_to_tx) { +uint8_t spi_tx_data(uint32_t slave_id, uint8_t tx_from_internal, uint8_t * tx_buffer, uint16_t ln_to_tx) { uint8_t out = SPI_UKNOWN; @@ -318,7 +375,7 @@ uint8_t spi_tx_data(uint32_t slave_id, uint8_t * tx_buffer, uint16_t ln_to_tx) { spi_current_tx_cntr = 0; // check if external or internal buffer shall be used - if (tx_buffer == 0) { + if (tx_from_internal == SPI_TX_FROM_INTERNAL) { spi_tx_buffer_ptr = spi_tx_buffer; // check if internal buffer has enought room for data @@ -358,10 +415,11 @@ uint8_t spi_tx_data(uint32_t slave_id, uint8_t * tx_buffer, uint16_t ln_to_tx) { /** * Initiate full duplex communication with the slave. After this call the SPI bus - * will be enabled and all data from tx_buffer will be send. SPI bus will be disabled - * after requested amount of data will be received or timeout occured. + * will be enabled and all data from tx_buffer will be send. After transmitting all bytes + * the master will transmit 0xFF on MOSI in the loop, until requested number of bytes + * will be received. Then SPI is disabled */ -uint8_t spi_rx_tx_data(uint32_t slave_id, uint8_t * rx_buffer, uint8_t * tx_buffer, uint16_t ln_to_rx, uint16_t ln_to_tx) { +uint8_t spi_rx_tx_data(uint32_t slave_id, uint8_t tx_from_internal, uint8_t * rx_buffer, uint8_t * tx_buffer, uint16_t ln_to_rx, uint16_t ln_to_tx) { uint8_t out = SPI_UKNOWN; @@ -404,7 +462,7 @@ uint8_t spi_rx_tx_data(uint32_t slave_id, uint8_t * rx_buffer, uint8_t * tx_buff } // check if external TX buffer shall be user or not - if (tx_buffer == 0) { + if (tx_from_internal == SPI_TX_FROM_INTERNAL) { spi_tx_buffer_ptr = spi_tx_buffer; // check if internal buffer has enought room for data @@ -432,9 +490,6 @@ uint8_t spi_rx_tx_data(uint32_t slave_id, uint8_t * rx_buffer, uint8_t * tx_buff spi_tx_bytes_rq = ln_to_tx; } - // latch a timestamp when reception has been triggered - spi_timestamp_rx_start = master_time; - // // set first byte for transmission // SPI2->DR = spi_tx_buffer_ptr[0]; @@ -485,11 +540,28 @@ uint8_t spi_wait_for_comms_done(void) { } void spi_reset_errors(void) { - if (spi_rx_state == SPI_RX_ERROR_MODF || spi_rx_state == SPI_RX_ERROR_OVERRUN || spi_rx_state == SPI_RX_ERROR_TIMEOUT) { + if (spi_rx_state == SPI_RX_ERROR_MODF || spi_rx_state == SPI_RX_ERROR_OVERRUN) { spi_rx_state = SPI_RX_IDLE; } } +spi_rx_state_t spi_get_rx_state(void) { + return spi_rx_state; +} + +spi_tx_state_t spi_get_tx_state(void) { + return spi_tx_state; +} + +uint32_t spi_get_current_slave(void) { + if (spi_rx_state != SPI_RX_RXING && spi_tx_state != SPI_TX_TXING) { + return 0; + } + else { + return spi_current_slave; + } +} + void spi_irq_handler(void) { // The RXNE flag is set depending on the FRXTH bit value in the SPIx_CR2 register: @@ -636,77 +708,3 @@ void spi_irq_handler(void) { spi_disable(1); } } - -/** - * This function should be caller from SysTick Interrupt - */ -void spi_timeout_handler(void) { - - if (spi_rx_state == SPI_RX_RXING) { - if (master_time - spi_timestamp_rx_start > SPI_RX_ERROR_TIMEOUT) { - spi_rx_state = SPI_RX_ERROR_TIMEOUT; - spi_tx_state = SPI_TX_IDLE; - - spi_disable(1); - } - } - } - -void spi_enable(uint8_t cs_assert) { - - // delay between asserting chip select and starting SPI - volatile int delay = 0; - - SPI2->CR2 |= SPI_CR2_ERRIE; - SPI2->CR2 |= SPI_CR2_RXNEIE; - SPI2->CR2 |= SPI_CR2_TXEIE; - - if (cs_assert != 0) { - LL_GPIO_ResetOutputPin((GPIO_TypeDef *)spi_slaves_cfg[spi_current_slave - 1][1], spi_slaves_cfg[spi_current_slave - 1][2]); - - // delay required by CS to SCLK Setup (MAX31865) - for (delay = 0; delay < SPI_CS_TO_SCLK_SETUP_DELAY; delay++); - } - - LL_SPI_Enable(SPI2); -} - -/** - * This function will disable SPI and close bus communication, optionally - * it can wait until the peripheral will be released - */ -void spi_disable(uint8_t immediately) { - - if (immediately == 0) { - while ((SPI2->SR & SPI_SR_BSY) != 0); - - LL_GPIO_SetOutputPin((GPIO_TypeDef *)spi_slaves_cfg[spi_current_slave - 1][1], spi_slaves_cfg[spi_current_slave - 1][2]); - - LL_SPI_Disable(SPI2); - - // disable all interrupts - SPI2->CR2 &= (0xFFFFFFFF ^ SPI_CR2_ERRIE); - SPI2->CR2 &= (0xFFFFFFFF ^ SPI_CR2_RXNEIE); - SPI2->CR2 &= (0xFFFFFFFF ^ SPI_CR2_TXEIE); - - if ((SPI2->SR & SPI_SR_RXNE) != 0) { - // clear RX fifo queue - do { - spi_garbage_counter++; - - spi_garbage = SPI2->DR & 0xFF; - } while ((SPI2->SR & SPI_SR_RXNE) != 0); - } - } - else { - LL_GPIO_SetOutputPin((GPIO_TypeDef *)spi_slaves_cfg[spi_current_slave - 1][1], spi_slaves_cfg[spi_current_slave - 1][2]); - - // disable all interrupts - SPI2->CR2 &= (0xFFFFFFFF ^ SPI_CR2_ERRIE); - SPI2->CR2 &= (0xFFFFFFFF ^ SPI_CR2_RXNEIE); - SPI2->CR2 &= (0xFFFFFFFF ^ SPI_CR2_TXEIE); - - LL_SPI_Disable(SPI2); - } - -} diff --git a/system/src/drivers/max31865.c b/system/src/drivers/max31865.c index 5680f71..7e4b01e 100644 --- a/system/src/drivers/max31865.c +++ b/system/src/drivers/max31865.c @@ -7,6 +7,26 @@ #include "drivers/max31865.h" +typedef enum max31865_pool_state_t { + MAX_IDLE, + MAX_INITIALIZED, + MAX_ERROR, + MAX_MEASUREMENT_STARTED, + MAX_REGISTER_REQUESTED, + MAX_SHUTDOWN, + MAX_POWER_OFF +}max31865_pool_state_t; + + +max31865_pool_state_t max31865_current_state = MAX_IDLE; + +/** + * This variable is incremented from 0 up to 9 to pause measurement + * state machine into MAX_SHUTDOWN state. When it reach 9 measurement + * is triggered + */ +uint8_t max31865_shutdown_ticks = 0; + /** * 1 - bias on * 0 - bias on @@ -48,6 +68,9 @@ uint8_t max31865_filter_select = 0; uint8_t max31865_buffer[3] = {0u}; +/** + * Set to one if MAX has been initialized correctly + */ uint8_t max31865_ok = 0; /** @@ -68,8 +91,44 @@ static uint8_t max31865_get_config_register(void) { return out; } +static void max31865_request_registers(void) { + + uint8_t result = 0; + + // check if SPI is busy now + if (spi_get_current_slave() == 0) { + // read adres of configuation register + max31865_buffer[0] = 0x00; + max31865_buffer[1] = 0x00; + + // read data for verifiaction + result = spi_rx_tx_data(1, SPI_TX_FROM_EXTERNAL, SPI_USE_INTERNAL_RX_BUF, max31865_buffer, 10, 1); + } + else { + max31865_current_state = MAX_ERROR; + } +} + +static void max31865_send_config_measurement(void) { + uint8_t result = 0; + + // check if SPI is busy now + if (spi_get_current_slave() == 0) { + // read adres of configuation register + max31865_buffer[0] = 0x80; + max31865_buffer[1] = max31865_get_config_register(); + + spi_tx_data(1, SPI_TX_FROM_EXTERNAL, max31865_buffer, 2); + } + else { + max31865_current_state = MAX_ERROR; + } +} + void max31865_init(uint8_t rdt_type) { + uint8_t * rx_data; + if (rdt_type == MAX_3WIRE) { max31865_rdt_sensor_type = 1; } @@ -84,30 +143,75 @@ void max31865_init(uint8_t rdt_type) { max31865_conversion_mode = 1; - max31865_buffer[0] = 0x80; - max31865_buffer[1] = max31865_get_config_register(); +// max31865_buffer[0] = 0x80; +// max31865_buffer[1] = max31865_get_config_register(); +// +// spi_tx_data(1, SPI_TX_FROM_EXTERNAL, max31865_buffer, 2); - spi_tx_data(1, max31865_buffer, 2); + max31865_send_config_measurement(); spi_wait_for_comms_done(); - // read adres of configuation register - max31865_buffer[0] = 0x00; - max31865_buffer[1] = 0x00; +// // read adres of configuation register +// max31865_buffer[0] = 0x00; +// max31865_buffer[1] = 0x00; +// +// // read data for verifiaction +// spi_rx_tx_data(1, SPI_TX_FROM_EXTERNAL, SPI_USE_INTERNAL_RX_BUF, max31865_buffer, 30, 1); - // read data for verifiaction - spi_rx_tx_data(1, 0, max31865_buffer, 30, 1); + max31865_request_registers(); spi_wait_for_comms_done(); - if (max31865_buffer[0] == max31865_get_config_register()) { + rx_data = spi_get_rx_data(); + + if (rx_data[0] == max31865_get_config_register()) { max31865_ok = 1; } + else { + max31865_ok = 0; + } } -void max31865_start_measurement(void) { +/** + * This pooler shall be called in two seconds interval + */ +void max31865_pool(void) { + switch (max31865_current_state) { + case MAX_IDLE: + // MAX31865 is powered up but not initialized + if (max31865_rdt_sensor_type == 1) { + max31865_init(MAX_3WIRE); + } + else { + max31865_init(MAX_4WIRE); + } + + max31865_current_state = MAX_INITIALIZED; + break; + case MAX_INITIALIZED: + // initialized and ready to start measurement + max31865_start_singleshot = 1; + + + break; + case MAX_ERROR: + break; + case MAX_MEASUREMENT_STARTED: + break; + case MAX_REGISTER_REQUESTED: + break; + case MAX_SHUTDOWN: + // MAX31965 is powered up and initialized but PT bias is disabled + // and no measurement is ongoing + break; + case MAX_POWER_OFF: + // supply voltage for MAX31865 is powered off and no communication + // is currently possible + break; + } } int32_t max31865_get_result(max31865_qf_t * quality_factor) {