From 9c6f88964ffa3214f582691f62ad8be2ccb07191 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20=C5=BDaitl=C3=ADk?= Date: Thu, 30 Sep 2021 16:49:08 +0200 Subject: [PATCH 1/3] Renamed some definitions of the EEPROM addresses. Implemented Holding registers write and read --- fw/Core/Inc/config.h | 28 +++++--- fw/Core/Src/config.c | 20 ++++-- fw/Core/Src/main.c | 156 ++++++++++++++++++++++++++++++++++--------- 3 files changed, 157 insertions(+), 47 deletions(-) diff --git a/fw/Core/Inc/config.h b/fw/Core/Inc/config.h index c398e99..cb891da 100644 --- a/fw/Core/Inc/config.h +++ b/fw/Core/Inc/config.h @@ -48,6 +48,10 @@ config_read(&config); * Device description data can be accessed using direct readout from the memory * Device configuration data can be accessed using config_t struct. */ +#define CONFIG_DEFAULT_LED_ON 1 +#define CONFIG_DEFAULT_LED_ALERT1_LIMIT 1000 +#define CONFIG_DEFAULT_LED_ALERT2_LIMIT 2000 + #define MODBUS_ADDR_LENGTH 2 #define CONFIG_LED_ON_LENGTH 2 #define CONFIG_LED_ALERT1_LENGTH 2 @@ -58,21 +62,23 @@ config_read(&config); #define REVISION_LENGTH 16 #define SERIAL_NUMBER_LENGTH 64 +#define EEPROM_EMPTY_BYTE 0x00 + #define EEPROM_ADDR_START ((uint32_t)0x08080000) #define EEPROM_ADDR_END ((uint32_t)0x080801FF) -#define CONFIG_EEPROM_ADDR_MODBUS_ADDR EEPROM_ADDR_START -#define CONFIG_EEPROM_ADDR_LED_ON_ADDR CONFIG_EEPROM_ADDR_MODBUS_ADDR + MODBUS_ADDR_LENGTH -#define CONFIG_EEPROM_ADDR_LED_ALERT1_ADDR CONFIG_EEPROM_ADDR_LED_ON_ADDR + CONFIG_LED_ON_LENGTH -#define CONFIG_EEPROM_ADDR_LED_ALERT2_ADDR CONFIG_EEPROM_ADDR_LED_ALERT1_ADDR + CONFIG_LED_ALERT1_LENGTH -#define CONFIG_EEPROM_ADDR_VENDOR_NAME CONFIG_EEPROM_ADDR_LED_ALERT2_ADDR + CONFIG_LED_ALERT2_LENGTH -#define CONFIG_EEPROM_ADDR_PRODUCT_CODE CONFIG_EEPROM_ADDR_VENDOR_NAME + VENDOR_NAME_LENGTH -#define CONFIG_EEPROM_ADDR_PRODUCT_NAME CONFIG_EEPROM_ADDR_PRODUCT_CODE + PRODUCT_CODE_LENGTH -#define CONFIG_EEPROM_ADDR_REVISION CONFIG_EEPROM_ADDR_PRODUCT_NAME + PRODUCT_NAME_LENGTH -#define CONFIG_EEPROM_ADDR_SERIAL_NUMBER CONFIG_EEPROM_ADDR_REVISION + REVISION_LENGTH +#define CONFIG_EEPROM_ADDR_MODBUS_ADDR (EEPROM_ADDR_START) +#define CONFIG_EEPROM_ADDR_LED_ON (CONFIG_EEPROM_ADDR_MODBUS_ADDR + MODBUS_ADDR_LENGTH) +#define CONFIG_EEPROM_ADDR_LED_ALERT1 (CONFIG_EEPROM_ADDR_LED_ON + CONFIG_LED_ON_LENGTH) +#define CONFIG_EEPROM_ADDR_LED_ALERT2 (CONFIG_EEPROM_ADDR_LED_ALERT1 + CONFIG_LED_ALERT1_LENGTH) +#define CONFIG_EEPROM_ADDR_VENDOR_NAME (CONFIG_EEPROM_ADDR_LED_ALERT2 + CONFIG_LED_ALERT2_LENGTH) +#define CONFIG_EEPROM_ADDR_PRODUCT_CODE (CONFIG_EEPROM_ADDR_VENDOR_NAME + VENDOR_NAME_LENGTH) +#define CONFIG_EEPROM_ADDR_PRODUCT_NAME (CONFIG_EEPROM_ADDR_PRODUCT_CODE + PRODUCT_CODE_LENGTH) +#define CONFIG_EEPROM_ADDR_REVISION (CONFIG_EEPROM_ADDR_PRODUCT_NAME + PRODUCT_NAME_LENGTH) +#define CONFIG_EEPROM_ADDR_SERIAL_NUMBER (CONFIG_EEPROM_ADDR_REVISION + REVISION_LENGTH) -#define FLASH_PEKEY1 0x89ABCDEF -#define FLASH_PEKEY2 0x02030405 +#define FLASH_PEKEY1 ((uint32_t)0x89ABCDEF) +#define FLASH_PEKEY2 ((uint32_t)0x02030405) #define CONFIG_OK 0 #define CONFIG_ERROR -1 diff --git a/fw/Core/Src/config.c b/fw/Core/Src/config.c index f809f09..0018a0c 100644 --- a/fw/Core/Src/config.c +++ b/fw/Core/Src/config.c @@ -21,9 +21,17 @@ static int8_t eeprom_program_halfword(uint32_t addr, uint16_t ee_data); int8_t config_read(config_t *config) { config->modbus_addr = *(uint16_t *) (CONFIG_EEPROM_ADDR_MODBUS_ADDR); - config->led_on = *(uint16_t *) (CONFIG_EEPROM_ADDR_LED_ON_ADDR); - config->led_co2_alert_limit1 = *(uint16_t *) (CONFIG_EEPROM_ADDR_LED_ALERT1_ADDR); - config->led_co2_alert_limit2 = *(uint16_t *) (CONFIG_EEPROM_ADDR_LED_ALERT2_ADDR); + config->led_on = *(uint16_t *) (CONFIG_EEPROM_ADDR_LED_ON); + config->led_co2_alert_limit1 = *(uint16_t *) (CONFIG_EEPROM_ADDR_LED_ALERT1); + config->led_co2_alert_limit2 = *(uint16_t *) (CONFIG_EEPROM_ADDR_LED_ALERT2); + + /* Check if the EEPROM is initialized - do not check LED ON, that is 1 or 0 */ + if ((config->modbus_addr == EEPROM_EMPTY_BYTE) || + (config->led_co2_alert_limit1 == EEPROM_EMPTY_BYTE) || + (config->led_co2_alert_limit2 == EEPROM_EMPTY_BYTE)) + { + return CONFIG_ERROR; + } return CONFIG_OK; } @@ -44,19 +52,19 @@ int8_t config_write(config_t *config) } /* Write LED ON */ - if (eeprom_program_byte(CONFIG_EEPROM_ADDR_LED_ON_ADDR, config->led_on) != EEPROM_OK) + if (eeprom_program_byte(CONFIG_EEPROM_ADDR_LED_ON, config->led_on) != EEPROM_OK) { return EEPROM_WRITE_ERROR; } /* Write LED CO2 ALERT LIMIT 1 */ - if (eeprom_program_halfword(CONFIG_EEPROM_ADDR_LED_ALERT1_ADDR, config->led_co2_alert_limit1) != EEPROM_OK) + if (eeprom_program_halfword(CONFIG_EEPROM_ADDR_LED_ALERT1, config->led_co2_alert_limit1) != EEPROM_OK) { return EEPROM_WRITE_ERROR; } /* Write LED CO2 ALERT LIMIT 2 */ - if (eeprom_program_halfword(CONFIG_EEPROM_ADDR_LED_ALERT2_ADDR, config->led_co2_alert_limit2) != EEPROM_OK) + if (eeprom_program_halfword(CONFIG_EEPROM_ADDR_LED_ALERT2, config->led_co2_alert_limit2) != EEPROM_OK) { return EEPROM_WRITE_ERROR; } diff --git a/fw/Core/Src/main.c b/fw/Core/Src/main.c index 9993b8e..532011e 100644 --- a/fw/Core/Src/main.c +++ b/fw/Core/Src/main.c @@ -77,12 +77,30 @@ enum { REGISTER_NUM_RH_SCD4x = 30014, REGISTER_NUM_T_SHT4x_SIGNED = 30015, REGISTER_NUM_T_SCD4x_SIGNED = 30016 -} register_numbers; +} data_registers_numbers; + +enum { + REGISTER_NUM_LED_ON = 40001, + REGISTER_NUM_CO2_ALERT_LIMIT1 = 40002, + REGISTER_NUM_CO2_ALERT_LIMIT2 = 40003, + REGISTER_NUM_MODBUS_ADDR = 40004 +} config_registers_numbers; + +enum { + REGISTER_NUM_VENDOR_NAME = 30010, + REGISTER_NUM_PRODUCT_CODE = 30011, + REGISTER_NUM_REVISION = 30012, + REGISTER_NUM_PRODUCT_NAME = 30013, + REGISTER_NUM_SERIAL_NUMBER = 30014 +} identification_registers_numbers; /* Variables to store the measured data */ int CO2, T_SCD4x, RH_SCD4x; int T_SHT4x, RH_SHT4x; uint16_t sps30_measured_data[10]; + +/* Struct to store the sensor config */ +config_t sensor_config; /* USER CODE END PV */ /* Private function prototypes -----------------------------------------------*/ @@ -100,35 +118,104 @@ void LPUART1_TX_Buffer(uint8_t* buffer_tx, uint8_t buffer_tx_len); int8_t modbus_slave_callback(modbus_transaction_t *transaction) { uint16_t register_number = transaction->register_number; - if (transaction->function_code == MODBUS_READ_INPUT_REGISTERS) { - for (int i = 0; i < transaction->register_count; i++, register_number++) { - switch (register_number) { - case REGISTER_NUM_CO2: - transaction->input_registers[i] = (uint16_t)CO2; - break; - case REGISTER_NUM_T_SHT4x: - transaction->input_registers[i] = (uint16_t)T_SHT4x; - break; - case REGISTER_NUM_RH_SHT4x: - transaction->input_registers[i] = (uint16_t)RH_SHT4x; - break; - case REGISTER_NUM_T_SCD4x: - transaction->input_registers[i] = (uint16_t)T_SCD4x; - break; - case REGISTER_NUM_RH_SCD4x: - transaction->input_registers[i] = (uint16_t)RH_SCD4x; - break; - case REGISTER_NUM_T_SHT4x_SIGNED: - transaction->input_registers_signed[i] = (int16_t)T_SHT4x; - break; - case REGISTER_NUM_T_SCD4x_SIGNED: - transaction->input_registers_signed[i] = (int16_t)T_SCD4x; - break; - default: - return MODBUS_ERROR_FUNCTION_NOT_IMPLEMENTED; + switch (transaction->function_code) + { + case MODBUS_READ_INPUT_REGISTERS: + for (int i = 0; i < transaction->register_count; i++, register_number++) + { + switch (register_number) + { + case REGISTER_NUM_CO2: + transaction->input_registers[i] = (uint16_t)CO2; + break; + case REGISTER_NUM_T_SHT4x: + transaction->input_registers[i] = (uint16_t)T_SHT4x; + break; + case REGISTER_NUM_RH_SHT4x: + transaction->input_registers[i] = (uint16_t)RH_SHT4x; + break; + case REGISTER_NUM_T_SCD4x: + transaction->input_registers[i] = (uint16_t)T_SCD4x; + break; + case REGISTER_NUM_RH_SCD4x: + transaction->input_registers[i] = (uint16_t)RH_SCD4x; + break; + case REGISTER_NUM_T_SHT4x_SIGNED: + transaction->input_registers_signed[i] = (int16_t)T_SHT4x; + break; + case REGISTER_NUM_T_SCD4x_SIGNED: + transaction->input_registers_signed[i] = (int16_t)T_SCD4x; + break; + default: + return MODBUS_ERROR_FUNCTION_NOT_IMPLEMENTED; + } } - } - return MODBUS_OK; + return MODBUS_OK; + case MODBUS_READ_HOLDING_REGISTERS: + for (int i = 0; i < transaction->register_count; i++, register_number++) + { + switch (register_number) + { + case REGISTER_NUM_LED_ON: + transaction->holding_registers[i] = (uint16_t)(sensor_config.led_on); + break; + case REGISTER_NUM_CO2_ALERT_LIMIT1: + transaction->holding_registers[i] = (uint16_t)(sensor_config.led_co2_alert_limit1); + break; + case REGISTER_NUM_CO2_ALERT_LIMIT2: + transaction->holding_registers[i] = (uint16_t)(sensor_config.led_co2_alert_limit2); + break; + case REGISTER_NUM_MODBUS_ADDR: + transaction->holding_registers[i] = (uint16_t)(sensor_config.modbus_addr); + break; + default: + return MODBUS_ERROR_FUNCTION_NOT_IMPLEMENTED; + } + } + return MODBUS_OK; + case MODBUS_WRITE_SINGLE_REGISTER: + switch (register_number) + { + case REGISTER_NUM_LED_ON: + sensor_config.led_on = (uint8_t) transaction->holding_registers[0]; + break; + case REGISTER_NUM_CO2_ALERT_LIMIT1: + sensor_config.led_co2_alert_limit1 = (uint16_t) transaction->holding_registers[0]; + break; + case REGISTER_NUM_CO2_ALERT_LIMIT2: + sensor_config.led_co2_alert_limit2 = (uint16_t) transaction->holding_registers[0]; + break; + case REGISTER_NUM_MODBUS_ADDR: + sensor_config.modbus_addr = (uint16_t) transaction->holding_registers[0]; + break; + default: + return MODBUS_ERROR_FUNCTION_NOT_IMPLEMENTED; + } + return MODBUS_OK; + case MODBUS_WRITE_MULTIPLE_REGISTERS: + for (int i = 0; i < transaction->register_count; i++, register_number++) + { + switch (register_number) + { + case REGISTER_NUM_LED_ON: + sensor_config.led_on = (uint8_t) transaction->holding_registers[i]; + break; + case REGISTER_NUM_CO2_ALERT_LIMIT1: + sensor_config.led_co2_alert_limit1 = (uint16_t) transaction->holding_registers[i]; + break; + case REGISTER_NUM_CO2_ALERT_LIMIT2: + sensor_config.led_co2_alert_limit2 = (uint16_t) transaction->holding_registers[i]; + break; + case REGISTER_NUM_MODBUS_ADDR: + sensor_config.modbus_addr = (uint16_t) transaction->holding_registers[i]; + break; + default: + return MODBUS_ERROR_FUNCTION_NOT_IMPLEMENTED; + } + } + return MODBUS_OK; + default: + return MODBUS_ERROR_FUNCTION_NOT_IMPLEMENTED; } /* Catch-all error */ return MODBUS_ERROR_FUNCTION_NOT_IMPLEMENTED; /* nothing implemented yet! TODO */ @@ -196,7 +283,16 @@ int main(void) i2c_context.i2c = I2C1; i2c_init(&i2c_context); - modbus_slave_set_address(0x11); + /* Read config from EEPROM - if unsuccessful, set the default values*/ + int8_t config_read_status = config_read(&sensor_config); + if (config_read_status != CONFIG_OK) + { + sensor_config.modbus_addr = MODBUS_DEFAULT_SLAVE_ADDRESS; + sensor_config.led_co2_alert_limit1 = CONFIG_DEFAULT_LED_ALERT1_LIMIT; + sensor_config.led_co2_alert_limit2 = CONFIG_DEFAULT_LED_ALERT2_LIMIT; + sensor_config.led_on = CONFIG_DEFAULT_LED_ON; + } + modbus_slave_set_address(sensor_config.modbus_addr); scd4x_start_periodic_measurement(); uint8_t scd4x_is_connected = 1; From 80a50d57cf7f5f775f88c1a7a9ff85491152fecb Mon Sep 17 00:00:00 2001 From: David Zaitlik Date: Thu, 30 Sep 2021 15:02:15 +0000 Subject: [PATCH 2/3] Add README.md --- README.md | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..709858b --- /dev/null +++ b/README.md @@ -0,0 +1,32 @@ +## MODBUS Registers + +### Input Registers + +|Value|Register| +|---|---| +|CO2 | 30010| +|SHT4x | 30011| +|RH SHT4x | 30012| +|T SCD4x | 30013| +|RH SCD4x | 30014| +|T SHT4x SIGNED | 30015| +|T SCD4x SIGNED | 30016| + +### Holding Registers + +|Value|Register| +|---|---| +|LED ON | 40001| +|CO2 ALERT LIMIT1 | 40002| +|CO2 ALERT LIMIT2 | 40003| +|MODBUS ADDR | 40004| + +### Device Information Registers + +|Value|Register| +|---|---| +|VENDOR NAME | 30010| +|PRODUCT CODE | 30011| +|REVISION | 30012| +|PRODUCT NAME | 30013| +|SERIAL NUMBER | 30014| From 5244fe768f8c539a31ec471392fc1b26c055c977 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20=C5=BDaitl=C3=ADk?= Date: Thu, 30 Sep 2021 17:43:29 +0200 Subject: [PATCH 3/3] Added CO2 Level LED indication. --- fw/Core/Inc/config.h | 4 +-- fw/Core/Src/main.c | 65 ++++++++++++++++++++++++++++++-------------- 2 files changed, 47 insertions(+), 22 deletions(-) diff --git a/fw/Core/Inc/config.h b/fw/Core/Inc/config.h index cb891da..c2d0f24 100644 --- a/fw/Core/Inc/config.h +++ b/fw/Core/Inc/config.h @@ -49,8 +49,8 @@ config_read(&config); * Device configuration data can be accessed using config_t struct. */ #define CONFIG_DEFAULT_LED_ON 1 -#define CONFIG_DEFAULT_LED_ALERT1_LIMIT 1000 -#define CONFIG_DEFAULT_LED_ALERT2_LIMIT 2000 +#define CONFIG_DEFAULT_LED_ALERT1_LIMIT 1500 +#define CONFIG_DEFAULT_LED_ALERT2_LIMIT 3000 #define MODBUS_ADDR_LENGTH 2 #define CONFIG_LED_ON_LENGTH 2 diff --git a/fw/Core/Src/main.c b/fw/Core/Src/main.c index 532011e..79f6571 100644 --- a/fw/Core/Src/main.c +++ b/fw/Core/Src/main.c @@ -267,22 +267,15 @@ int main(void) MX_LPUART1_UART_Init(); MX_TIM21_Init(); /* USER CODE BEGIN 2 */ + + /* Turn on MAGENTA LED to signal startup state */ + LL_GPIO_ResetOutputPin(LED_R_GPIO_Port, LED_R_Pin); + LL_GPIO_SetOutputPin(LED_G_GPIO_Port, LED_G_Pin); + LL_GPIO_ResetOutputPin(LED_B_GPIO_Port, LED_B_Pin); + /* Enable I2C for sensors */ LL_I2C_Enable(I2C1); - /* Enable UART for RS485 */ - LL_LPUART_Enable(LPUART1); - - /* Start the timer for measurement triggering */ - LL_TIM_EnableCounter(TIM21); - LL_TIM_EnableIT_UPDATE(TIM21); - /*LL_TIM_GenerateEvent_UPDATE(TIM2);*/ - - /* I2C context init (for SHT4x and SCD4x) */ - i2c_context_t i2c_context; - i2c_context.i2c = I2C1; - i2c_init(&i2c_context); - /* Read config from EEPROM - if unsuccessful, set the default values*/ int8_t config_read_status = config_read(&sensor_config); if (config_read_status != CONFIG_OK) @@ -292,8 +285,22 @@ int main(void) sensor_config.led_co2_alert_limit2 = CONFIG_DEFAULT_LED_ALERT2_LIMIT; sensor_config.led_on = CONFIG_DEFAULT_LED_ON; } + + /* Set the modbus address */ modbus_slave_set_address(sensor_config.modbus_addr); + /* Enable UART for RS485 */ + LL_LPUART_Enable(LPUART1); + + /* Start the timer for measurement triggering */ + LL_TIM_EnableCounter(TIM21); + LL_TIM_EnableIT_UPDATE(TIM21); + + /* I2C context init (for SHT4x and SCD4x) */ + i2c_context_t i2c_context; + i2c_context.i2c = I2C1; + i2c_init(&i2c_context); + scd4x_start_periodic_measurement(); uint8_t scd4x_is_connected = 1; uint8_t sps30_is_connected = 0; @@ -321,8 +328,6 @@ int main(void) /* SPS30 Init Time: max 30000 ms (datasheet pg. 2) */ LL_mDelay(1000); - /* Turn on LED to signal ready state */ - LL_GPIO_ResetOutputPin(LED_B_GPIO_Port, LED_B_Pin); /* Enter the main loop */ while (1) @@ -347,12 +352,32 @@ int main(void) { sps30_read_measured_values(sps30_measured_data, 10); } - - /* Toggle LED for now */ - /* TODO: Remove LED Toggle */ - LL_GPIO_TogglePin(LED_B_GPIO_Port, LED_B_Pin); - /* TODO: Process data and light a desired color of LED */ + /* TODO: Add hystheresis */ + + if (CO2 <= sensor_config.led_co2_alert_limit1) + { + /* CO2 is OK -> BLUE */ + /* TODO: Decide if blue or green */ + LL_GPIO_SetOutputPin(LED_R_GPIO_Port, LED_R_Pin); + LL_GPIO_SetOutputPin(LED_G_GPIO_Port, LED_G_Pin); + LL_GPIO_ResetOutputPin(LED_B_GPIO_Port, LED_B_Pin); + + } else if ((sensor_config.led_co2_alert_limit1 < CO2) && (CO2 <= sensor_config.led_co2_alert_limit2)) + { + /* CO2 is NOT OK -> YELLOW */ + LL_GPIO_ResetOutputPin(LED_R_GPIO_Port, LED_R_Pin); + LL_GPIO_ResetOutputPin(LED_G_GPIO_Port, LED_G_Pin); + LL_GPIO_SetOutputPin(LED_B_GPIO_Port, LED_B_Pin); + + } else if (sensor_config.led_co2_alert_limit2 < CO2) + { + /* CO2 is CRITICAL -> RED */ + LL_GPIO_ResetOutputPin(LED_R_GPIO_Port, LED_R_Pin); + LL_GPIO_SetOutputPin(LED_G_GPIO_Port, LED_G_Pin); + LL_GPIO_SetOutputPin(LED_B_GPIO_Port, LED_B_Pin); + + } /* Reset the TIM21 Elapsed Period Flag */ tim21_elapsed_period = 0;