2021-01-02 23:03:59 +01:00
|
|
|
/* Reflow Oven Controller
|
|
|
|
*
|
|
|
|
* Copyright (C) 2021 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/spi-eeprom.h>
|
|
|
|
#include <stm-periph/spi.h>
|
|
|
|
#include <reflow-controller/periph-config/spi-eeprom-hwcfg.h>
|
|
|
|
#include <stm-periph/rcc-manager.h>
|
|
|
|
#include <stm-periph/stm32-gpio-macros.h>
|
2021-01-08 18:39:54 +01:00
|
|
|
#include <stddef.h>
|
2021-01-02 23:03:59 +01:00
|
|
|
|
|
|
|
#define EEPROM_SIZE 0x200
|
|
|
|
#define EEPROM_PAGE_SIZE 16
|
|
|
|
|
2021-01-08 18:39:54 +01:00
|
|
|
#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
|
|
|
|
|
2021-01-02 23:03:59 +01:00
|
|
|
static stm_spi_handle eeprom_spi_handle;
|
|
|
|
|
|
|
|
static void eeprom_cs_activate(void)
|
|
|
|
{
|
|
|
|
SPI_EEPROM_SPI_PORT->ODR &= ~(1<<SPI_EEPROM_CS_PIN);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void eeprom_cs_deactivate(void)
|
|
|
|
{
|
|
|
|
SPI_EEPROM_SPI_PORT->ODR |= (1<<SPI_EEPROM_CS_PIN);
|
|
|
|
}
|
|
|
|
|
|
|
|
int spi_eeprom_init()
|
|
|
|
{
|
|
|
|
static struct stm_spi_dev spi_dev;
|
|
|
|
struct stm_spi_settings settings;
|
|
|
|
|
|
|
|
rcc_manager_enable_clock(&SPI_EEPROM_SPI_PORT_RCC_REG, BITMASK_TO_BITNO(SPI_EEPROM_SPI_PORT_RCC_MASK));
|
|
|
|
|
|
|
|
SPI_EEPROM_SPI_PORT->MODER &= MODER_DELETE(SPI_EEPROM_CS_PIN) & MODER_DELETE(SPI_EEPROM_MISO_PIN) &
|
|
|
|
MODER_DELETE(SPI_EEPROM_MOSI_PIN) & MODER_DELETE(SPI_EEPROM_SCK_PIN);
|
|
|
|
SPI_EEPROM_SPI_PORT->MODER |= ALTFUNC(SPI_EEPROM_MISO_PIN) | ALTFUNC(SPI_EEPROM_SCK_PIN) | ALTFUNC(SPI_EEPROM_MOSI_PIN);
|
|
|
|
SPI_EEPROM_SPI_PORT->MODER |= OUTPUT(SPI_EEPROM_CS_PIN);
|
|
|
|
|
|
|
|
SETAF(SPI_EEPROM_SPI_PORT, SPI_EEPROM_MISO_PIN, SPI_EEPROM_SPI_ALTFUNC_NO);
|
|
|
|
SETAF(SPI_EEPROM_SPI_PORT, SPI_EEPROM_MOSI_PIN, SPI_EEPROM_SPI_ALTFUNC_NO);
|
|
|
|
SETAF(SPI_EEPROM_SPI_PORT, SPI_EEPROM_SCK_PIN, SPI_EEPROM_SPI_ALTFUNC_NO);
|
|
|
|
|
|
|
|
eeprom_cs_deactivate();
|
|
|
|
|
|
|
|
settings.cpha = false;
|
|
|
|
settings.cpol = false;
|
|
|
|
settings.cs_activate = eeprom_cs_activate;
|
|
|
|
settings.cs_deactivate = eeprom_cs_deactivate;
|
|
|
|
settings.master = true;
|
|
|
|
settings.msb_first = true;
|
2021-01-08 18:39:54 +01:00
|
|
|
settings.prescaler = SPI_PRSC_DIV16;
|
2021-01-02 23:03:59 +01:00
|
|
|
eeprom_spi_handle = spi_init(&spi_dev, SPI1, &settings);
|
|
|
|
|
|
|
|
if (eeprom_spi_handle)
|
|
|
|
return 0;
|
|
|
|
else
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
void spi_eeprom_deinit()
|
|
|
|
{
|
|
|
|
spi_deinit(eeprom_spi_handle);
|
|
|
|
|
|
|
|
SPI_EEPROM_SPI_PORT->MODER &= MODER_DELETE(SPI_EEPROM_CS_PIN) & MODER_DELETE(SPI_EEPROM_MISO_PIN) &
|
|
|
|
MODER_DELETE(SPI_EEPROM_MOSI_PIN) & MODER_DELETE(SPI_EEPROM_SCK_PIN);
|
|
|
|
|
|
|
|
rcc_manager_disable_clock(&SPI_EEPROM_SPI_PORT_RCC_REG, BITMASK_TO_BITNO(SPI_EEPROM_SPI_PORT_RCC_MASK));
|
|
|
|
}
|
|
|
|
|
|
|
|
uint8_t spi_eeprom_read_status_reg(void)
|
|
|
|
{
|
|
|
|
uint8_t buff[2] = {0x05, 0x00};
|
|
|
|
|
|
|
|
(void)spi_transfer(eeprom_spi_handle, buff, buff, 2, true);
|
|
|
|
|
|
|
|
return buff[1];
|
|
|
|
}
|
|
|
|
|
2021-01-08 18:39:54 +01:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2021-01-02 23:03:59 +01:00
|
|
|
int spi_eeprom_read(uint32_t addr, uint8_t *rx_buff, uint32_t count)
|
|
|
|
{
|
|
|
|
int ret = 0;
|
2021-01-08 18:39:54 +01:00
|
|
|
int retry = 250;
|
|
|
|
uint8_t status_reg;
|
|
|
|
uint8_t cmd[2];
|
2021-01-02 23:03:59 +01:00
|
|
|
|
|
|
|
if (!rx_buff || !count)
|
|
|
|
return -1000;
|
|
|
|
|
|
|
|
if (addr >= EEPROM_SIZE)
|
|
|
|
return -1001;
|
|
|
|
|
2021-01-08 18:39:54 +01:00
|
|
|
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;
|
2021-01-02 23:03:59 +01:00
|
|
|
|
2021-01-08 18:39:54 +01:00
|
|
|
cmd[0] = EEPROM_CMD_READ_DATA;
|
|
|
|
if (addr & (1<<8))
|
|
|
|
cmd[0] |= (1U<<3);
|
|
|
|
cmd[1] = (uint8_t)(addr & 0xFF);
|
2021-01-02 23:03:59 +01:00
|
|
|
|
|
|
|
eeprom_cs_activate();
|
2021-01-08 18:39:54 +01:00
|
|
|
spi_transfer(eeprom_spi_handle, cmd, NULL, 2, false);
|
|
|
|
spi_transfer(eeprom_spi_handle, NULL, rx_buff, count, false);
|
|
|
|
eeprom_cs_deactivate();
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
2021-01-02 23:03:59 +01:00
|
|
|
|
2021-01-08 18:39:54 +01:00
|
|
|
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);
|
2021-01-02 23:03:59 +01:00
|
|
|
|
2021-01-08 18:39:54 +01:00
|
|
|
cmd[0] = EEPROM_CMD_WRITE_DATA | ((addr & (1<<8)) ? (1<<4) : 0);
|
|
|
|
cmd[1] = (uint8_t)(addr & 0xFF);
|
2021-01-02 23:03:59 +01:00
|
|
|
|
2021-01-08 18:39:54 +01:00
|
|
|
eeprom_cs_activate();
|
|
|
|
spi_transfer(eeprom_spi_handle, cmd, NULL, 2, false);
|
|
|
|
spi_transfer(eeprom_spi_handle, data, NULL, len, false);
|
2021-01-02 23:03:59 +01:00
|
|
|
eeprom_cs_deactivate();
|
2021-01-08 18:39:54 +01:00
|
|
|
}
|
2021-01-02 23:03:59 +01:00
|
|
|
|
2021-01-08 18:39:54 +01:00
|
|
|
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;
|
2021-01-02 23:03:59 +01:00
|
|
|
}
|
|
|
|
|
2021-01-08 18:39:54 +01:00
|
|
|
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;
|
|
|
|
}
|