Implement EEPROM and use it for saving the calibration
This commit is contained in:
parent
0e233a257c
commit
3a07347f48
@ -45,7 +45,7 @@ CFILES += rotary-encoder.c button.c
|
||||
CFILES += ui/lcd.c ui/menu.c ui/gui.c
|
||||
CFILES += fatfs/diskio.c fatfs/ff.c fatfs/ffsystem.c fatfs/ffunicode.c fatfs/shimatta_sdio_driver/shimatta_sdio.c
|
||||
CFILES += pid-controller.c oven-driver.c
|
||||
CFILES += settings/settings.c settings/settings-sd-card.c settings/spi-eeprom.c
|
||||
CFILES += settings/settings.c settings/settings-sd-card.c settings/spi-eeprom.c settings/settings-eeprom.c
|
||||
CFILES += stm-periph/crc-unit.c
|
||||
CFILES += safety/safety-adc.c safety/safety-controller.c safety/watchdog.c safety/fault.c safety/safety-memory.c safety/stack-check.c
|
||||
CFILES += hw-version-detect.c
|
||||
|
@ -0,0 +1,32 @@
|
||||
/* Reflow Oven Controller
|
||||
*
|
||||
* Copyright (C) 2020 Mario Hüttel <mario.huettel@gmx.net>
|
||||
*
|
||||
* This file is part of the Reflow Oven Controller Project.
|
||||
*
|
||||
* The reflow oven controller is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* The Reflow Oven Control Firmware is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with the reflow oven controller project.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __SETTINGS_SETTINGS_EEPROM_H__
|
||||
#define __SETTINGS_SETTINGS_EEPROM_H__
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
bool settings_eeprom_detect_and_prepare(void);
|
||||
|
||||
int settings_eeprom_save_calibration(float sens, float offset, bool active);
|
||||
|
||||
int settings_eeprom_load_calibration(float *sens, float *offset, bool *active);
|
||||
|
||||
#endif /* __SETTINGS_SETTINGS_EEPROM_H__ */
|
@ -53,4 +53,6 @@ int settings_load_calibration(float *sens_dev, float *offset);
|
||||
|
||||
enum settings_load_result settings_load_pid_oven_parameters(struct oven_pid_settings *settings);
|
||||
|
||||
void settings_setup(void);
|
||||
|
||||
#endif /* __SETTINGS_SETTINGS_H__ */
|
||||
|
@ -22,6 +22,8 @@
|
||||
#define __SETTINGS_SPI_EEPROM_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
|
||||
int spi_eeprom_init();
|
||||
|
||||
@ -29,8 +31,12 @@ void spi_eeprom_deinit();
|
||||
|
||||
int spi_eeprom_read(uint32_t addr, uint8_t *rx_buff, uint32_t count);
|
||||
|
||||
bool spi_eeprom_write_in_progress(void);
|
||||
|
||||
int spi_eeprom_write(uint32_t addr, const uint8_t *data, uint32_t count);
|
||||
|
||||
uint8_t spi_eeprom_read_status_reg(void);
|
||||
|
||||
bool spi_eeprom_check_connected(void);
|
||||
|
||||
#endif /* __SETTINGS_SPI_EEPROM_H__ */
|
||||
|
@ -46,6 +46,7 @@
|
||||
#include <reflow-controller/safety/safety-memory.h>
|
||||
#include <reflow-controller/safety/fault.h>
|
||||
#include <reflow-controller/updater/updater.h>
|
||||
|
||||
#include <reflow-controller/settings/spi-eeprom.h>
|
||||
|
||||
static void setup_nvic_priorities(void)
|
||||
@ -179,7 +180,7 @@ static inline void setup_system(void)
|
||||
loudspeaker_setup();
|
||||
gui_init();
|
||||
uart_gpio_config();
|
||||
spi_eeprom_init();
|
||||
settings_setup();
|
||||
|
||||
handle_boot_status();
|
||||
|
||||
@ -210,8 +211,15 @@ int main(void)
|
||||
shellmatta_handle_t shell_handle;
|
||||
int menu_wait_request;
|
||||
uint64_t quarter_sec_timestamp = 0ULL;
|
||||
|
||||
setup_system();
|
||||
|
||||
/* Try load the calibration. This will only succeed if there's an EEPROM */
|
||||
status = settings_load_calibration(&sens, &offset);
|
||||
if (!status) {
|
||||
adc_pt1000_set_resistance_calibration(offset, sens, true);
|
||||
}
|
||||
|
||||
shell_handle = shell_init(write_shell_callback);
|
||||
shell_print_motd(shell_handle);
|
||||
|
||||
|
140
stm-firmware/settings/settings-eeprom.c
Normal file
140
stm-firmware/settings/settings-eeprom.c
Normal file
@ -0,0 +1,140 @@
|
||||
/* Reflow Oven Controller
|
||||
*
|
||||
* Copyright (C) 2020 Mario Hüttel <mario.huettel@gmx.net>
|
||||
*
|
||||
* This file is part of the Reflow Oven Controller Project.
|
||||
*
|
||||
* The reflow oven controller is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* The Reflow Oven Control Firmware is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with the reflow oven controller project.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <reflow-controller/settings/settings-eeprom.h>
|
||||
#include <reflow-controller/settings/spi-eeprom.h>
|
||||
#include <stm-periph/crc-unit.h>
|
||||
#include <string.h>
|
||||
|
||||
#define EEPROM_HEADER_MAGIC 0xA5
|
||||
#define EEPROM_HEADER_COMP_VER 0xFF
|
||||
|
||||
static const uint8_t expected_header[2] = {EEPROM_HEADER_MAGIC, EEPROM_HEADER_COMP_VER};
|
||||
|
||||
#define EEPROM_CALIBRATION_BASE_ADDR 0x2
|
||||
struct eeprom_calibration_settings {
|
||||
uint32_t active;
|
||||
float offset;
|
||||
float sens_dev;
|
||||
uint32_t crc;
|
||||
};
|
||||
|
||||
static bool check_eeprom_header(void)
|
||||
{
|
||||
uint8_t header[2] = {0};
|
||||
|
||||
/* Try to read the magic header and the compatible version */
|
||||
spi_eeprom_read(0x0, header, 2);
|
||||
if (memcmp(header, expected_header, 2))
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
static void settings_eeprom_zero()
|
||||
{
|
||||
settings_eeprom_save_calibration(0.0f, 0.0f, false);
|
||||
}
|
||||
|
||||
bool settings_eeprom_detect_and_prepare(void)
|
||||
{
|
||||
bool eeprom_ready = false;;
|
||||
|
||||
int res;
|
||||
|
||||
crc_unit_init();
|
||||
res = spi_eeprom_init();
|
||||
if (res)
|
||||
goto ret_deinit_crc;
|
||||
|
||||
if (!spi_eeprom_check_connected())
|
||||
goto ret_deinit_crc;
|
||||
|
||||
if (check_eeprom_header() == false) {
|
||||
/* Try to write a new header and check it again */
|
||||
spi_eeprom_write(0, expected_header, sizeof(expected_header));
|
||||
while (spi_eeprom_write_in_progress());
|
||||
if (check_eeprom_header() == false) {
|
||||
goto ret_deinit_crc;
|
||||
} else {
|
||||
/* Sucessfully written new header
|
||||
* Zero out the rest of the settings
|
||||
*/
|
||||
settings_eeprom_zero();
|
||||
eeprom_ready = true;
|
||||
}
|
||||
} else {
|
||||
eeprom_ready = true;
|
||||
}
|
||||
|
||||
goto exit;
|
||||
|
||||
ret_deinit_crc:
|
||||
crc_unit_deinit();
|
||||
|
||||
exit:
|
||||
return eeprom_ready;
|
||||
}
|
||||
|
||||
int settings_eeprom_save_calibration(float sens, float offset, bool active)
|
||||
{
|
||||
int res;
|
||||
|
||||
struct eeprom_calibration_settings sett;
|
||||
|
||||
sett.active = (active ? 0xAABBCCDD : 0);
|
||||
sett.offset = offset;
|
||||
sett.sens_dev = sens;
|
||||
|
||||
crc_unit_reset();
|
||||
crc_unit_input_array((const uint32_t *)&sett, (sizeof(sett) / 4)-1);
|
||||
sett.crc = crc_unit_get_crc();
|
||||
|
||||
res = spi_eeprom_write(EEPROM_CALIBRATION_BASE_ADDR, (uint8_t *)&sett, sizeof(sett));
|
||||
|
||||
if (res)
|
||||
return -2;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
int settings_eeprom_load_calibration(float *sens, float *offset, bool *active)
|
||||
{
|
||||
struct eeprom_calibration_settings sett;
|
||||
int res;
|
||||
|
||||
res = spi_eeprom_read(EEPROM_CALIBRATION_BASE_ADDR, (uint8_t *)&sett, sizeof(sett));
|
||||
if (res)
|
||||
return -2;
|
||||
|
||||
crc_unit_reset();
|
||||
crc_unit_input_array((const uint32_t *)&sett, sizeof(sett) / 4 - 1);
|
||||
if (crc_unit_get_crc() == sett.crc) {
|
||||
if (sens)
|
||||
*sens = sett.sens_dev;
|
||||
if (offset)
|
||||
*offset = sett.offset;
|
||||
if (active)
|
||||
*active = (sett.active ? true : false);
|
||||
return 0;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
@ -20,19 +20,47 @@
|
||||
|
||||
#include <reflow-controller/settings/settings.h>
|
||||
#include <reflow-controller/settings/settings-sd-card.h>
|
||||
#include <reflow-controller/settings/settings-eeprom.h>
|
||||
#include <reflow-controller/hw-version-detect.h>
|
||||
|
||||
bool settings_use_eeprom;
|
||||
|
||||
int settings_save_calibration(float sens_deviation, float offset, bool active)
|
||||
{
|
||||
/* There is no other configuration location besides the SD card (yet) */
|
||||
if (settings_use_eeprom)
|
||||
return settings_eeprom_save_calibration(sens_deviation, offset, active);
|
||||
else
|
||||
return sd_card_settings_save_calibration(sens_deviation, offset, active);
|
||||
}
|
||||
|
||||
int settings_load_calibration(float *sens_dev, float *offset)
|
||||
{
|
||||
return sd_card_settings_try_load_calibration(sens_dev, offset);
|
||||
bool active;
|
||||
int res;
|
||||
|
||||
if (settings_use_eeprom) {
|
||||
res =settings_eeprom_load_calibration(sens_dev, offset, &active);
|
||||
if (!res && !active)
|
||||
res = -1;
|
||||
} else {
|
||||
res = -1;
|
||||
}
|
||||
|
||||
if (res)
|
||||
res = sd_card_settings_try_load_calibration(sens_dev, offset);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
enum settings_load_result settings_load_pid_oven_parameters(struct oven_pid_settings *settings)
|
||||
{
|
||||
return sd_card_settings_load_pid_oven_parameters(settings);
|
||||
}
|
||||
|
||||
void settings_setup(void)
|
||||
{
|
||||
if (get_pcb_hardware_version() >= HW_REV_V1_3)
|
||||
settings_use_eeprom = settings_eeprom_detect_and_prepare();
|
||||
else
|
||||
settings_use_eeprom = false;
|
||||
}
|
||||
|
@ -23,10 +23,23 @@
|
||||
#include <reflow-controller/periph-config/spi-eeprom-hwcfg.h>
|
||||
#include <stm-periph/rcc-manager.h>
|
||||
#include <stm-periph/stm32-gpio-macros.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#define EEPROM_SIZE 0x200
|
||||
#define EEPROM_PAGE_SIZE 16
|
||||
|
||||
#define EEPROM_STATUS_REG_WIP (0x1U)
|
||||
#define EEPROM_STATUS_REG_WEL (0x1U << 1)
|
||||
#define EEPROM_STATUS_REG_BP0 (0x1U << 2)
|
||||
#define EEPROM_STATUS_REG_BP1 (0x1U << 3)
|
||||
|
||||
#define EEPROM_CMD_READ_STATUS 0x05
|
||||
#define EEPROM_CMD_WRITE_STATUS 0x01
|
||||
#define EEPROM_CMD_READ_DATA 0x3
|
||||
#define EEPROM_CMD_WRITE_DATA 0x2
|
||||
#define EEPROM_CMD_WREN 0x6
|
||||
#define EEPROM_CMD_WRDI 0x4
|
||||
|
||||
static stm_spi_handle eeprom_spi_handle;
|
||||
|
||||
static void eeprom_cs_activate(void)
|
||||
@ -63,7 +76,7 @@ int spi_eeprom_init()
|
||||
settings.cs_deactivate = eeprom_cs_deactivate;
|
||||
settings.master = true;
|
||||
settings.msb_first = true;
|
||||
settings.prescaler = SPI_PRSC_DIV64;
|
||||
settings.prescaler = SPI_PRSC_DIV16;
|
||||
eeprom_spi_handle = spi_init(&spi_dev, SPI1, &settings);
|
||||
|
||||
if (eeprom_spi_handle)
|
||||
@ -91,9 +104,24 @@ uint8_t spi_eeprom_read_status_reg(void)
|
||||
return buff[1];
|
||||
}
|
||||
|
||||
static void spi_eeprom_set_write_enable_latch(bool status)
|
||||
{
|
||||
uint8_t cmd;
|
||||
|
||||
if (status)
|
||||
cmd = EEPROM_CMD_WREN;
|
||||
else
|
||||
cmd = EEPROM_CMD_WRDI;
|
||||
|
||||
(void)spi_transfer(eeprom_spi_handle, &cmd, NULL, 1, true);
|
||||
}
|
||||
|
||||
int spi_eeprom_read(uint32_t addr, uint8_t *rx_buff, uint32_t count)
|
||||
{
|
||||
int ret = 0;
|
||||
int retry = 250;
|
||||
uint8_t status_reg;
|
||||
uint8_t cmd[2];
|
||||
|
||||
if (!rx_buff || !count)
|
||||
return -1000;
|
||||
@ -101,15 +129,100 @@ int spi_eeprom_read(uint32_t addr, uint8_t *rx_buff, uint32_t count)
|
||||
if (addr >= EEPROM_SIZE)
|
||||
return -1001;
|
||||
|
||||
do {
|
||||
status_reg = spi_eeprom_read_status_reg();
|
||||
} while ((status_reg & EEPROM_STATUS_REG_WIP) && retry--);
|
||||
|
||||
if (status_reg & EEPROM_STATUS_REG_WIP)
|
||||
return -1;
|
||||
|
||||
cmd[0] = EEPROM_CMD_READ_DATA;
|
||||
if (addr & (1<<8))
|
||||
cmd[0] |= (1U<<3);
|
||||
cmd[1] = (uint8_t)(addr & 0xFF);
|
||||
|
||||
eeprom_cs_activate();
|
||||
|
||||
|
||||
|
||||
spi_transfer(eeprom_spi_handle, cmd, NULL, 2, false);
|
||||
spi_transfer(eeprom_spi_handle, NULL, rx_buff, count, false);
|
||||
eeprom_cs_deactivate();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int spi_eeprom_write(uint32_t addr, const uint8_t *data, uint32_t count);
|
||||
bool spi_eeprom_write_in_progress(void)
|
||||
{
|
||||
uint8_t status_reg;
|
||||
|
||||
status_reg = spi_eeprom_read_status_reg();
|
||||
|
||||
if (status_reg & EEPROM_STATUS_REG_WIP)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
static void spi_eeprom_do_write_page(uint32_t addr, const uint8_t *data, uint8_t len)
|
||||
{
|
||||
uint8_t cmd[2];
|
||||
|
||||
/* Wait for the previous write to finish */
|
||||
while (spi_eeprom_write_in_progress());
|
||||
/* Set the write enable latch */
|
||||
spi_eeprom_set_write_enable_latch(true);
|
||||
|
||||
cmd[0] = EEPROM_CMD_WRITE_DATA | ((addr & (1<<8)) ? (1<<4) : 0);
|
||||
cmd[1] = (uint8_t)(addr & 0xFF);
|
||||
|
||||
eeprom_cs_activate();
|
||||
spi_transfer(eeprom_spi_handle, cmd, NULL, 2, false);
|
||||
spi_transfer(eeprom_spi_handle, data, NULL, len, false);
|
||||
eeprom_cs_deactivate();
|
||||
}
|
||||
|
||||
int spi_eeprom_write(uint32_t addr, const uint8_t *data, uint32_t count)
|
||||
{
|
||||
const uint8_t *ptr = data;
|
||||
uint32_t transfer_len;
|
||||
|
||||
if (!data || !count)
|
||||
return -1000;
|
||||
|
||||
if (addr >= EEPROM_SIZE)
|
||||
return -1001;
|
||||
|
||||
while (count > 0) {
|
||||
/* Calculate size for current page transfer */
|
||||
transfer_len = EEPROM_PAGE_SIZE - (addr % EEPROM_PAGE_SIZE);
|
||||
if (transfer_len > count)
|
||||
transfer_len = count;
|
||||
|
||||
spi_eeprom_do_write_page(addr, ptr, transfer_len);
|
||||
count -= transfer_len;
|
||||
addr += transfer_len;
|
||||
ptr += transfer_len;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool spi_eeprom_check_connected(void)
|
||||
{
|
||||
uint8_t status_reg;
|
||||
|
||||
/* Try to set write enable latch */
|
||||
spi_eeprom_set_write_enable_latch(true);
|
||||
|
||||
/* Read back status register */
|
||||
status_reg = spi_eeprom_read_status_reg();
|
||||
if (!(status_reg & EEPROM_STATUS_REG_WEL))
|
||||
return false;
|
||||
|
||||
/* Clear the latch */
|
||||
spi_eeprom_set_write_enable_latch(false);
|
||||
/* Read back status register */
|
||||
status_reg = spi_eeprom_read_status_reg();
|
||||
if ((status_reg & EEPROM_STATUS_REG_WEL))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user