Merge branch 'flash'
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
* config.h
|
||||
*
|
||||
* Created on: Sep 5, 2021
|
||||
* Author: dukenuc
|
||||
* Author: david
|
||||
*/
|
||||
|
||||
#ifndef INC_CONFIG_H_
|
||||
@@ -10,36 +10,96 @@
|
||||
|
||||
/* TODO: add comments to everything */
|
||||
|
||||
/* EXAMPLE of USAGE */
|
||||
/*
|
||||
config_t new_config;
|
||||
new_config.led_co2_alert_limit1 = 1000;
|
||||
new_config.led_co2_alert_limit2 = 2000;
|
||||
new_config.led_on = 1;
|
||||
new_config.modbus_addr = 0x11;
|
||||
config_write(&new_config);
|
||||
|
||||
config_t config;
|
||||
config_read(&config);
|
||||
*/
|
||||
|
||||
#include "stdint.h"
|
||||
#include "stm32l0xx.h"
|
||||
/* DESCRIPTION OF THE DATA STRUCTURE */
|
||||
/*
|
||||
* Data are divided into two groups:
|
||||
* A) DEVICE DESCRIPTION
|
||||
* Can not be changed by the user.
|
||||
* These data can be only read.
|
||||
* These data are:
|
||||
* * VENDOR NAME
|
||||
* * PRODUCT CODE
|
||||
* * PRODUCT NAME
|
||||
* * REVISION
|
||||
* * SERIAL NUMBER
|
||||
* B) DEVICE CONFIGURATION
|
||||
* Can be changed by the user.
|
||||
* These data are:
|
||||
* * MODBUS ADDRESS - Modbus Address of the device. Default is 254
|
||||
* * LED ON - Whether the CO2 Level Indication LED should be on or off
|
||||
* * LED CO2 ALERT LIMIT 1 - CO2 Level when the LED color changes Green<->Yellow
|
||||
* * LED CO2 ALERT LIMIT 2 - CO2 Level when the LED color changes Yellow<->Red
|
||||
*
|
||||
* Device description data can be accessed using direct readout from the memory
|
||||
* Device configuration data can be accessed using config_t struct.
|
||||
*/
|
||||
#define MODBUS_ADDR_LENGTH 2
|
||||
#define CONFIG_LED_ON_LENGTH 2
|
||||
#define CONFIG_LED_ALERT1_LENGTH 2
|
||||
#define CONFIG_LED_ALERT2_LENGTH 2
|
||||
#define VENDOR_NAME_LENGTH 64
|
||||
#define PRODUCT_CODE_LENGTH 64
|
||||
#define PRODUCT_NAME_LENGTH 64
|
||||
#define REVISION_LENGTH 16
|
||||
#define SERIAL_NUMBER_LENGTH 64
|
||||
|
||||
#define VENDOR_NAME_LENGTH 64
|
||||
#define PRODUCT_CODE_LENGTH 64
|
||||
#define PRODUCT_NAME_LENGTH 64
|
||||
#define REVISION_LENGTH 16
|
||||
#define SERIAL_NUMBER_LENGTH 64
|
||||
#define EEPROM_ADDR_START ((uint32_t)0x08080000)
|
||||
#define EEPROM_ADDR_END ((uint32_t)0x080801FF)
|
||||
|
||||
#define CONFIG_OK 0
|
||||
#define CONFIG_ERROR -1
|
||||
#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 FLASH_PEKEY1 0x89ABCDEF
|
||||
#define FLASH_PEKEY2 0x02030405
|
||||
|
||||
#define CONFIG_OK 0
|
||||
#define CONFIG_ERROR -1
|
||||
|
||||
#define EEPROM_OK 0
|
||||
#define EEPROM_ERROR -1
|
||||
#define EEPROM_UNLOCK_ERROR -2
|
||||
#define EEPROM_LOCK_ERROR -3
|
||||
#define EEPROM_WRITE_ERROR -4
|
||||
#define EEPROM_ADDR_ERROR -5
|
||||
|
||||
#define SYSTICK_FREQ_HZ 12000000
|
||||
#define EEPROM_TIMEOUT_MAX_MS_INV 200
|
||||
|
||||
typedef struct
|
||||
{
|
||||
/* DEVICE ID */
|
||||
uint8_t vendor_name[VENDOR_NAME_LENGTH];
|
||||
uint8_t product_code[PRODUCT_CODE_LENGTH];
|
||||
uint8_t product_name[PRODUCT_NAME_LENGTH];
|
||||
uint8_t revision[REVISION_LENGTH];
|
||||
uint8_t serial_number[SERIAL_NUMBER_LENGTH];
|
||||
|
||||
/* DEVICE SPECIFIC CONFIG */
|
||||
/* DEVICE CONFIG */
|
||||
uint8_t led_on;
|
||||
uint16_t led_co2_alert_limit1;
|
||||
uint16_t led_co2_alert_limit2;
|
||||
|
||||
/* MODBUS CONFIG */
|
||||
uint16_t modbus_addr;
|
||||
} config_t;
|
||||
|
||||
int8_t read_config(config_t *config);
|
||||
|
||||
int8_t write_config(config_t *config);
|
||||
int8_t config_read(config_t *config);
|
||||
int8_t config_write(config_t *config);
|
||||
|
||||
#endif /* INC_CONFIG_H_ */
|
||||
|
||||
|
||||
@@ -53,6 +53,7 @@ extern "C" {
|
||||
#include "sht4x.h"
|
||||
#include "sps30.h"
|
||||
#include "modbus.h"
|
||||
#include "config.h"
|
||||
/* USER CODE END Includes */
|
||||
|
||||
/* Exported types ------------------------------------------------------------*/
|
||||
|
||||
@@ -2,17 +2,163 @@
|
||||
* config.c
|
||||
*
|
||||
* Created on: Sep 5, 2021
|
||||
* Author: dukenuc
|
||||
* Author: david
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
int8_t read_config(config_t *config)
|
||||
/* Function to lock the EEPROM */
|
||||
static int8_t eeprom_lock(void);
|
||||
/* Function to unlock the EEPROM */
|
||||
static int8_t eeprom_unlock(void);
|
||||
/* Function to write one byte to the EEPROM */
|
||||
/* IMPORTANT: EEPROM must be unlocked first */
|
||||
static int8_t eeprom_program_byte(uint32_t addr, uint8_t ee_data);
|
||||
/* Function to write two bytes to the EEPROM */
|
||||
/* IMPORTANT: EEPROM must be unlocked first */
|
||||
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);
|
||||
return CONFIG_OK;
|
||||
}
|
||||
|
||||
int8_t write_config(config_t *config)
|
||||
int8_t config_write(config_t *config)
|
||||
{
|
||||
/* Unlock the EEPROM */
|
||||
if (eeprom_unlock() != EEPROM_OK)
|
||||
{
|
||||
return EEPROM_UNLOCK_ERROR;
|
||||
}
|
||||
/* Reset the ERASE and DATA bits in the FLASH_PECR register to disable any residual erase */
|
||||
FLASH->PECR = FLASH->PECR & ~(FLASH_PECR_ERASE | FLASH_PECR_DATA);
|
||||
|
||||
/* Write MODBUS ADDRESS */
|
||||
if (eeprom_program_halfword(CONFIG_EEPROM_ADDR_MODBUS_ADDR, config->modbus_addr) != EEPROM_OK)
|
||||
{
|
||||
return EEPROM_WRITE_ERROR;
|
||||
}
|
||||
|
||||
/* Write LED ON */
|
||||
if (eeprom_program_byte(CONFIG_EEPROM_ADDR_LED_ON_ADDR, 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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
return EEPROM_WRITE_ERROR;
|
||||
}
|
||||
|
||||
/* Lock EEPROM*/
|
||||
if (eeprom_lock() != EEPROM_OK)
|
||||
{
|
||||
return EEPROM_LOCK_ERROR;
|
||||
}
|
||||
return CONFIG_OK;
|
||||
}
|
||||
|
||||
static int8_t eeprom_lock(void)
|
||||
{
|
||||
uint32_t tick_start = SysTick->VAL;
|
||||
while ((FLASH->SR & FLASH_SR_BSY) != 0) /* Wait for FLASH to be free */
|
||||
{
|
||||
/* Timeout test */
|
||||
/* The maximum writing time is 3.94ms (half-word) */
|
||||
uint32_t tick_last = SysTick->VAL;
|
||||
uint32_t tick_diff;
|
||||
if (tick_start <= tick_last)
|
||||
{
|
||||
tick_diff = tick_last - tick_start;
|
||||
} else
|
||||
{
|
||||
tick_diff = (0xFFFFFFFF - tick_last) + tick_start;
|
||||
}
|
||||
|
||||
/* If the time difference is more than 5ms */
|
||||
if (tick_diff >= (uint32_t)((uint32_t)SYSTICK_FREQ_HZ*(uint32_t)EEPROM_TIMEOUT_MAX_MS_INV))
|
||||
{
|
||||
return EEPROM_LOCK_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
FLASH->PECR = FLASH->PECR & ~(FLASH_PECR_ERRIE | FLASH_PECR_EOPIE); /* disable flash interrupts */
|
||||
FLASH->PECR = FLASH->PECR | FLASH_PECR_PELOCK; /* Lock memory with PELOCK */
|
||||
|
||||
return EEPROM_OK;
|
||||
}
|
||||
|
||||
static int8_t eeprom_unlock(void)
|
||||
{
|
||||
uint32_t tick_start = SysTick->VAL;
|
||||
while ((FLASH->SR & FLASH_SR_BSY) != 0) /* Wait for FLASH to be free */
|
||||
{
|
||||
/* Timeout test */
|
||||
/* The maximum writing time is 3.94ms (half-word) */
|
||||
uint32_t tick_last = SysTick->VAL;
|
||||
uint32_t tick_diff;
|
||||
if (tick_start <= tick_last)
|
||||
{
|
||||
tick_diff = tick_last - tick_start;
|
||||
} else
|
||||
{
|
||||
tick_diff = (0xFFFFFFFF - tick_last) + tick_start;
|
||||
}
|
||||
|
||||
/* If the time difference is more than 5ms */
|
||||
if (tick_diff >= (uint32_t)((uint32_t)SYSTICK_FREQ_HZ*(uint32_t)EEPROM_TIMEOUT_MAX_MS_INV))
|
||||
{
|
||||
return EEPROM_UNLOCK_ERROR;
|
||||
}
|
||||
}
|
||||
if ((FLASH->PECR & FLASH_PECR_PELOCK) != 0) /* If PELOCK is locked */
|
||||
{
|
||||
/* Unlock PELOCK */
|
||||
FLASH->PEKEYR = FLASH_PEKEY1; /* PEKEY1 */
|
||||
FLASH->PEKEYR = FLASH_PEKEY2; /* PEKEY2 */
|
||||
}
|
||||
FLASH->PECR = FLASH->PECR | (FLASH_PECR_ERRIE | FLASH_PECR_EOPIE); /* enable flash interrupts */
|
||||
return EEPROM_OK;
|
||||
}
|
||||
|
||||
static int8_t eeprom_program_byte(uint32_t addr, uint8_t ee_data)
|
||||
{
|
||||
if ((EEPROM_ADDR_START <= addr) && (addr <= EEPROM_ADDR_END - 1))
|
||||
{
|
||||
*(uint8_t *)(addr) = ee_data; /* write data to EEPROM */
|
||||
if (*(uint8_t *)(addr) != ee_data)
|
||||
{
|
||||
return EEPROM_WRITE_ERROR;
|
||||
}
|
||||
return EEPROM_OK;
|
||||
} else
|
||||
{
|
||||
return EEPROM_ADDR_ERROR;
|
||||
}
|
||||
}
|
||||
static int8_t eeprom_program_halfword(uint32_t addr, uint16_t ee_data)
|
||||
{
|
||||
if ((EEPROM_ADDR_START <= addr) && (addr <= EEPROM_ADDR_END - 2))
|
||||
{
|
||||
*(uint16_t *)(addr) = ee_data; /* write data to EEPROM */
|
||||
if (*(uint16_t *)(addr) != ee_data)
|
||||
{
|
||||
return EEPROM_WRITE_ERROR;
|
||||
}
|
||||
return EEPROM_OK;
|
||||
} else
|
||||
{
|
||||
return EEPROM_ADDR_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user