diff --git a/baro/baro.c b/baro/baro.c index 469dbf2..e9f8ef7 100644 --- a/baro/baro.c +++ b/baro/baro.c @@ -85,6 +85,12 @@ static BARO_STATUS write_reg uint8_t data /* In: Register contents */ ); +/* Configure/intialize the barometric pressure sensor */ +static BARO_STATUS baro_config + ( + BARO_CONFIG* config_ptr + ); + /* Load the compensation data from the baro sensor */ static BARO_STATUS load_cal_data ( @@ -236,7 +242,7 @@ return baro_status; * Configure the barometric pressure sensor * * * *******************************************************************************/ -BARO_STATUS baro_config +static BARO_STATUS baro_config ( BARO_CONFIG* config_ptr ) @@ -884,13 +890,13 @@ return baro_data_ready; /******************************************************************************* * * * PROCEDURE: * -* start_baro_read_IT * +* baro_start_read_IT * * * * DESCRIPTION: * * Receive baro data in interrupt mode. * * * *******************************************************************************/ -BARO_STATUS start_baro_read_IT +BARO_STATUS baro_start_read_IT ( void ) @@ -934,7 +940,7 @@ else return baro_status; } -} /* start_baro_read_IT */ +} /* baro_start_read_IT */ /******************************************************************************* @@ -944,7 +950,7 @@ else * * * DESCRIPTION: * * ISR for baro data reception. Heavy ISR. Consider moving processing to * -* get_baro_IT. * +* baro_get_IT. * * * *******************************************************************************/ BARO_STATUS baro_IT_handler @@ -997,13 +1003,13 @@ return baro_status; /******************************************************************************* * * * PROCEDURE: * -* get_baro_it * +* baro_get_IT * * * * DESCRIPTION: * * Getter function for IT baro data. * * * *******************************************************************************/ -BARO_STATUS get_baro_it +BARO_STATUS baro_get_IT ( float* pres_ptr, /* o: pressure */ float* temp_ptr /* o: temperature */ @@ -1018,9 +1024,9 @@ if( !baro_data_ready ) *temp_ptr = baro_temp_proc; return BARO_OK; -} /* get_baro_it */ +} /* baro_get_IT */ /******************************************************************************* * END OF FILE * -*******************************************************************************/ \ No newline at end of file +*******************************************************************************/ diff --git a/baro/baro.h b/baro/baro.h index 2a4847b..6ce979e 100644 --- a/baro/baro.h +++ b/baro/baro.h @@ -30,10 +30,15 @@ extern "C" { #include "stm32h7xx_hal.h" +#ifdef A0010 +#include "sdr_pin_defines_A0010.h" +#endif + /*------------------------------------------------------------------------------ Macros ------------------------------------------------------------------------------*/ +#ifdef A0002_REV2 /* I2C Device Params */ #define BARO_I2C_ADDR ( 0x76 << 1 ) /* 1110110 -> 0x76 */ @@ -80,7 +85,7 @@ extern "C" { /* Baro sensor command codes */ #define BARO_CMD_RESET ( 0xB6 ) #define BARO_CMD_FIFO_FLUSH ( 0xB0 ) - +#endif /*------------------------------------------------------------------------------ Typdefs @@ -95,9 +100,18 @@ typedef enum _BARO_STATUS BARO_UNRECOGNIZED_HAL_STATUS, BARO_UNSUPPORTED_CONFIG , BARO_UNRECOGNIZED_CHIP_ID , + #ifdef A00100 , + /* If the CRC check on r3 baro memory fails */ + BARO_INVALID_PROM, + #endif BARO_ERROR , BARO_CAL_ERROR , + #ifdef A0002_REV2 BARO_I2C_ERROR , + #endif + #ifdef A0010 + BARO_SPI_ERROR , + #endif BARO_CANNOT_RESET , BARO_FIFO_ERROR , BARO_BUSY @@ -112,6 +126,23 @@ typedef enum _BARO_SENSOR_ENABLES BARO_PRESS_TEMP_ENABLED = 3 } BARO_SENSOR_ENABLES; +#ifdef A0010 +/* Interrupt events for R3 version of driver. + * Takes similar approach to telemetry in mod. + * Events are in order of when they occure. + * Some events occur multiple times per + * data acquisition cycle. + */ +typedef enum _BARO_EVENT + { + BARO_EVENT_START_READ = 0, + BARO_EVENT_TX_CPLT, + BARO_EVENT_DELAY_ELAPSED, + BARO_EVENT_TXRX_CPLT + } BARO_EVENT; +#endif + +#ifdef A0002_REV2 /* Operating mode of baro sensor */ typedef enum _BARO_MODE { @@ -119,29 +150,52 @@ typedef enum _BARO_MODE BARO_FORCED_MODE = 1, BARO_NORMAL_MODE = 3 } BARO_MODE; - +#endif + /* Pressure Sensor Oversampling Settings */ typedef enum _BARO_PRESS_OSR_SETTING { + #ifdef A0002_REV2 BARO_PRESS_OSR_X1 = 0, BARO_PRESS_OSR_X2 , BARO_PRESS_OSR_X4 , BARO_PRESS_OSR_X8 , BARO_PRESS_OSR_X16 , BARO_PRESS_OSR_X32 + #endif + /* Prevent any possibility that vals get misinterpreted between revs */ + #ifdef A0010 + BARO_PRESS_OSR_X256 = 6, + BARO_PRESS_OSR_X512 , + BARO_PRESS_OSR_X1024 , + BARO_PRESS_OSR_X2048 , + BARO_PRESS_OSR_X4096 + #endif } BARO_PRESS_OSR_SETTING; /* Temperature Sensor Oversampling Settings */ typedef enum _BARO_TEMP_OSR_SETTING { + #ifdef A0002_REV2 BARO_TEMP_OSR_X1 = 0, BARO_TEMP_OSR_X2 , BARO_TEMP_OSR_X4 , BARO_TEMP_OSR_X8 , BARO_TEMP_OSR_X16 , BARO_TEMP_OSR_X32 + #endif + /* Prevent any possibility that vals get misinterpreted between revs */ + #ifdef A0010 + BARO_TEMP_OSR_X256 = 6, + BARO_TEMP_OSR_X512 , + BARO_TEMP_OSR_X1024 , + BARO_TEMP_OSR_X2048 , + BARO_TEMP_OSR_X4096 + #endif } BARO_TEMP_OSR_SETTING; + +#ifdef A0002_REV2 /* Sample Frequency settings */ typedef enum _BARO_ODR_SETTING { @@ -168,30 +222,39 @@ typedef enum _BARO_IIR_SETTING BARO_IIR_COEF_63 = 6, BARO_IIR_COEF_127 = 7 } BARO_IIR_SETTING; - +#endif + /* Baro sensor configuration settings struct */ typedef struct _BARO_CONFIG { /* Sensor enables */ BARO_SENSOR_ENABLES enable; - /* Operating mode */ - BARO_MODE mode; - /* Pressure Oversampling setting */ BARO_PRESS_OSR_SETTING press_OSR_setting; /* Temperature Oversampling setting */ BARO_TEMP_OSR_SETTING temp_OSR_setting; + #ifdef A0002_REV2 + /* Operating mode */ + BARO_MODE mode; + /* Sampling frequency */ BARO_ODR_SETTING ODR_setting; /* IIR Filter Coefficient Selection */ BARO_IIR_SETTING IIR_setting; - + #endif } BARO_CONFIG; + +/* These structs are static to the rev3 implementation. +* They should be for rev2 as well, but aren't. +* I'm leaving it this way for rev2 code because emulator +* depends on it. +*/ +#ifdef A0002_REV2 /* Baro calibration data struct in integer format */ typedef struct _BARO_CAL_DATA_INT { @@ -239,7 +302,7 @@ typedef struct _BARO_CAL_DATA float comp_temp; } BARO_CAL_DATA; - +#endif /*------------------------------------------------------------------------------ Function Prototypes @@ -250,20 +313,27 @@ BARO_STATUS baro_init ( BARO_CONFIG* config_ptr ); - -/* Configure/intialize the barometric pressure sensor */ -BARO_STATUS baro_config + +#ifdef A0002_REV2 +/* verifies sensor can be accessed */ +BARO_STATUS baro_get_device_id ( - BARO_CONFIG* config_ptr + uint8_t* baro_id ); +#endif +#ifdef A0010 /* verifies sensor can be accessed */ +/* The serial is 12 bits on the rev 3 sensor */ BARO_STATUS baro_get_device_id ( uint8_t* baro_id + uint16_t* baro_id ); +#endif - +/* Blocking implementations are not supported on r3 */ +#ifdef A0002_REV2 /* gets pressure data from sensor */ BARO_STATUS baro_get_pressure ( @@ -281,16 +351,41 @@ BARO_STATUS baro_get_altitude ( void ); - +#endif + /* returns the baro_data_ready flag */ bool baro_get_baro_data_ready ( void ); -BARO_STATUS start_baro_read_IT(); -BARO_STATUS baro_IT_handler(); -BARO_STATUS get_baro_it(float* pres_ptr, float* temp_ptr); +BARO_STATUS baro_start_read_IT + ( + void + ); +BARO_STATUS baro_get_IT + ( + float* pres_ptr, + float* temp_ptr + ); + +#ifdef A0002_REV2 +BARO_STATUS baro_IT_handler + ( + void + ); +#endif +#ifdef A0010 +/* R3 baro has more complicated data acquisition sequence. + * We thus need to prevent various race conditions; + * this required making a breaking API change. + * The approach is very similar to the telemetry module. + */ +BARO_STATUS baro_IT_handler + ( + BARO_EVENT update_cause; + ); +#endif #ifdef __cplusplus @@ -300,4 +395,4 @@ BARO_STATUS get_baro_it(float* pres_ptr, float* temp_ptr); /******************************************************************************* * END OF FILE * -*******************************************************************************/ \ No newline at end of file +*******************************************************************************/ diff --git a/baro/baro_r3.c b/baro/baro_r3.c new file mode 100644 index 0000000..07af821 --- /dev/null +++ b/baro/baro_r3.c @@ -0,0 +1,375 @@ +/** + ****************************************************************************** + * @file : baro_r3.c + * @brief : Driver for the MS5607-02BA03 barometer on FC rev 3. + ****************************************************************************** + * @copyright + * + * Copyright (c) 2026 Sun Devil Rocketry. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is covered under the + * BSD-3-Clause. + * + * https://opensource.org/license/bsd-3-clause + */ + +/* Includes ------------------------------------------------------------------*/ + +/* Standard */ +#include +#include + +/* Project */ +#include "main.h" +#include "error_sdr.h" +#include "stm32h7xx_hal.h" +#include "sdr_pin_defines_A0010.h" +#include "baro.h" + +/* Type Definitions ----------------------------------------------------------*/ + +/* Baro calibration data struct in integer format */ +typedef struct _BARO_CAL_DATA_INT + { + uint16_t par_c1; // Pressure Sensitity + uint16_t par_c2; // Pressure Offset + uint16_t par_c3; // Temp. Coeff. of Pressure Sensitivity + uint16_t par_c4; // Temp. Coeff. of Pressure Offset + uint16_t par_c5; // Reference Temperature + uint16_t par_c6; // Temp. Coeff. of Temperature + } BARO_CAL_DATA_INT; + +/* States for FSM to read data */ +typedef enum _BARO_READ_STATE + { + BARO_CONV_PRESSURE, // Start pressure Conversion + BARO_WAIT_PRESSURE, // Pressure Conversion Wait + BARO_READ_PRESSURE, // Start pressure ADC Read + BARO_CONV_TEMPERATURE, // Start Temp Conversion + BARO_WAIT_TEMPERATURE, // Temp Conversion Wait + BARO_READ_TEMPERATURE, // Start Temperature ADC Read + BARO_READ_FINISH, // Complete sensor reading + BARO_READ_DONE, // Done + BARO_READ_FAIL + } BARO_READ_STATE; +/* Global Variables ----------------------------------------------------------*/ + +/* Current Baro Sensor configuration */ +static BARO_CONFIG baro_configuration; + +/* Baro calibration coefficients for measurement compensation */ +static BARO_CAL_DATA_INT baro_cal_data; + +/* Store pre-generated commands for sensor conversion + * Derived from config, set during init + */ +static uint8_t pressure_cmd; +static uint8_t temperature_cmd; + +/* Store pre-calculated sensor conversion timeouts + * Derived from config, set during init, stored in microseconds + */ +static uint32_t pressure_timeout; +static uint32_t temperature_timeout; + +/* Raw SPI bytes with readings */ +uint8_t baro_raw_temp_buffer[3]; +uint8_t baro_raw_press_buffer[3]; + +/* State of barometer read process */ +static _Atomic BARO_READ_STATE baro_read_state = BARO_READ_FAIL; + +static BARO_STATUS success; + +/* Private function prototypes -----------------------------------------------*/ + +/* Some of these are probably good candidates for macros */ + +/* + * Implementation Notes + * I think we can create a TIM_OC_InitTypeDef, configure HAL_TIM_OC_ConfigChannel in a channel, + * and then run HAL_TIM_OC_Start. Our callback is then HAL_TIM_OC_DelayElapsedCallback(). + */ +static BARO_STATUS create_timer_interrupt // TODO actually implement + ( + uint32_t timeout_us + ); + +static BARO_STATUS clear_timer_interrupt // TODO actually implement + ( + void + ); + +static BARO_STATUS transmit_cmd_IT + ( + uint8_t command_byte + ); + +static BARO_STATUS transceive_adc_IT + ( + uint8_t* out_buffer + ); + +static void update_state + ( + BARO_READ_STATE next_state + ); + +/* Procedures ----------------------------------------------------------------*/ + +/* TODO + * - write baro_init and its helpers + * - write baro_get_IT (this is where the buffers will be converted to + * usable values and calculations applied to return the final float) + * - write the timer interrupt creation functions + */ + +/** + * @brief Check if barometer data is ready + * + * @details It looks at the barometer state machine status and checks if it + * is in a successful terminal state (BARO_READ_DONE, not BARO_READ_FAIL). + * + * @retval Ready status + */ +bool baro_get_baro_data_ready + ( + void + ) +{ +return baro_read_state == BARO_READ_DONE; +} + +/** + * @brief Initiate reading of baro via interrupt mode + * + * @details If baro_read_state is in a terminal state (OK or FAIL), this resets + * the state to the first state and calls the handler for the first time to + * start the process. If it is NOT in a terminal state, that means a read is already + * in progress, and this function will do nothing. + * + * @retval Status of the barometer + */ +BARO_STATUS baro_start_read_IT + ( + void + ) +{ +switch ( baro_read_state ) + { + case BARO_READ_FAIL: + + case BARO_READ_DONE: // No currently running read + baro_read_state = BARO_CONV_PRESSURE; + baro_IT_handler(BARO_START_READ); // Keep FSM logic in that function + break; + + default: // Read in progress + return BARO_BUSY; + } +} + +/** + * @brief Data acquisition finite state machine. + * + * @details This function must be called by three interrupt callbacks: + * SPI_TxCpltCallback(), HAL_SPI_TxRxCpltCallback(), and + * HAL_TIM_OC_DelayElapsedCallback(). These bring the read through a series of + * 7 states (plus a done and fail state), needed to account for timeouts required by the chip. + * You must pass in the corresponding event type for each one. + * + * @retval Status of the barometer + */ +BARO_STATUS baro_IT_handler + ( + BARO_EVENT update_cause + ) +{ +switch(baro_read_state) { + // TODO actually deal with chip select pin + case BARO_CONV_PRESSURE: + if( update_cause != BARO_EVENT_START_READ ) + { + /* Do nothing */ + return; + } + // 1. Called by baro_start_read_IT, start pressure conversion + success = transmit_cmd_IT(pressure_cmd); + update_state(BARO_WAIT_PRESSURE); + break; + case BARO_WAIT_PRESSURE: + if( update_cause != BARO_EVENT_TX_CPLT ) + { + /* Do nothing */ + return; + } + // 2. Called by SPI_TxCpltCallback(), create pressure conversion timeout + success = create_timer_interrupt(pressure_timeout); + update_state(BARO_READ_PRESSURE); + break; + case BARO_READ_PRESSURE: + if( update_cause != BARO_EVENT_DELAY_ELAPSED ) + { + /* Do nothing */ + return; + } + // 3. Called by HAL_TIM_OC_DelayElapsedCallback(), press temp ADC read + clear_timer_interrupt(); + success = transceive_adc_IT(baro_raw_press_buffer); + update_state(BARO_CONV_TEMPERATURE); + break; + case BARO_CONV_TEMPERATURE: + if( update_cause != BARO_EVENT_TXRX_CPLT ) + { + /* Do nothing */ + return; + } + // 4. Called by HAL_SPI_TxRxCpltCallback(), start temperature conversion + success = transmit_cmd_IT(temperature_cmd); + update_state(BARO_WAIT_TEMPERATURE); + break; + case BARO_WAIT_TEMPERATURE: + if( update_cause != BARO_EVENT_TX_CPLT ) + { + /* Do nothing */ + return; + } + // 5. Called by SPI_TxCpltCallback(), create temp conversion timeout + success = create_timer_interrupt(temperature_timeout); + update_state(BARO_READ_TEMPERATURE); + break; + case BARO_READ_TEMPERATURE: + if( update_cause != BARO_EVENT_DELAY_ELAPSED ) + { + /* Do nothing */ + return; + } + // 6. Called by HAL_TIM_OC_DelayElapsedCallback(), run temp ADC read + clear_timer_interrupt(); + success = transceive_adc_IT(baro_raw_press_buffer); + update_state(BARO_READ_FINISH); + break; + case BARO_READ_FINISH: + if( update_cause != BARO_EVENT_TXRX_CPLT ) + { + /* Do nothing */ + return; + } + // 7. Called by HAL_SPI_TxRxCpltCallback(), switch to done state. + success = BARO_OK; + update_state(BARO_READ_DONE); + break; + case BARO_READ_DONE: + // We're done. Nothing happens. + /* This state should never be entered during normal execution */ + debug_assert(true, ERROR_BARO_INVALID_STATE_ERROR); + success = BARO_OK; + break; + default: + /* This state should never be entered during normal execution */ + debug_assert(true, ERROR_BARO_INVALID_STATE_ERROR); + success = BARO_FAIL; // BARO_READ_FAIL or undefined state +} +return success; +} + +/* Helpers ----------------------------------------------------------------*/ + +/** + * @brief Creates a timer interrupt for at least the specified duration + * + * @details This uses the microseconds timer, adding the requested time + * to the current time in microseconds modulo the period, to avoid corner + * cases with overflows + * + * @param timeout_us The time to wait in microseconds + * + * @retval The status of the barometer + */ +static BARO_STATUS create_timer_interrupt // TODO actually implement + ( + uint32_t timeout_us + ) +{ + // This uses output capture without changing pin + // PSEUDOCODE + // Create a TIM_OC_InitTypeDef + // Set its pulse to __HAL_TIM_GET_COUNTER(&MICRO_TIM) + timeout_us + // Set its mode to TIM_OCMODE_TIMING + // etc... + // Configure the given TIM channel with this. + // Start the timer. Handlers are called in stm32h7xx_it.c +} + +/** + * @brief Transmits a single command byte to the baro + * + * @param command_byte The command byte to transmit. + * + * @retval The status of the barometer + */ +static BARO_STATUS transmit_cmd_IT + ( + uint8_t command_byte + ) +{ +HAL_StatusTypeDef success; +success = HAL_SPI_Transmit_IT(BARO_SPI, &command_byte, 1); + +if( success == HAL_OK ){ + return BARO_OK; +} else { + return BARO_SPI_ERROR; +} +} + +/** + * @brief Requests the 3 bytes of data currently in the ADC + * + * @param out_buffer The 3 byte buffer to place received SPI bytes in. + * + * @retval The status of the barometer + */ +static BARO_STATUS transceive_adc_IT + ( + uint8_t* out_buffer + ) +{ +/* The zero byte is the ADC command, and the last two are filler bytes */ +/* They should do nothing in the chip's command language */ +/* This could still be wrong, though. We'll need to test on real HW. */ +/* Each result is 24 bits (3 bytes) */ +uint8_t in_buffer[3] = {0x00, 0xFF, 0xFF}; + +HAL_StatusTypeDef success; +success = HAL_SPI_TransmitReceive_IT(BARO_SPI, &in_buffer, &out_buffer, 3); + +if( success == HAL_OK ){ + return BARO_OK; +} else { + return BARO_SPI_ERROR; +} +} + +/** + * @brief Moved to requested state if no fail conditions are detected + * + * @param next_state The baro read state to switch to. + */ +static void update_state + ( + BARO_READ_STATE next_state + ) +{ +if(success == BARO_OK) + { + baro_read_state = next_state; + } +else + { + baro_read_state = BARO_READ_FAIL; + } +}