Merge branch 'master' of gitlab.com:HDIoT/smart_household/wired_sensors/iaq_wired_sensor
This commit is contained in:
commit
cfc32b28c2
32
README.md
Normal file
32
README.md
Normal file
@ -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|
|
@ -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 1500
|
||||
#define CONFIG_DEFAULT_LED_ALERT2_LIMIT 3000
|
||||
|
||||
#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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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 */
|
||||
@ -180,24 +267,40 @@ 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);
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/* 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);
|
||||
/*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);
|
||||
|
||||
modbus_slave_set_address(0x11);
|
||||
|
||||
scd4x_start_periodic_measurement();
|
||||
uint8_t scd4x_is_connected = 1;
|
||||
uint8_t sps30_is_connected = 0;
|
||||
@ -225,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)
|
||||
@ -274,12 +375,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;
|
||||
|
Loading…
Reference in New Issue
Block a user