/* Reflow Oven Controller * * Copyright (C) 2021 Mario Hüttel * * 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 . */ #include #include #include #include #include #include #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) { SPI_EEPROM_SPI_PORT->ODR &= ~(1<ODR |= (1<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; settings.prescaler = SPI_PRSC_DIV16; 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]; } 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; 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; } 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; }