From bf08863de8ea44e3e276842ad7db83974baccadc Mon Sep 17 00:00:00 2001 From: jazzpi Date: Sun, 12 Jun 2022 21:05:42 +0200 Subject: [PATCH] Implement EEPROM bytewise read/write --- Core/Inc/EEPROM.h | 41 +++++++++++++++++++++ Core/Inc/stm32f4xx_it.h | 1 + Core/Src/EEPROM.c | 71 ++++++++++++++++++++++++++++++++++++ Core/Src/main.c | 6 +++ Core/Src/stm32f4xx_hal_msp.c | 5 +++ Core/Src/stm32f4xx_it.c | 15 ++++++++ Makefile | 2 +- STM32Make.make | 1 + ams-slave.ioc | 1 + 9 files changed, 142 insertions(+), 1 deletion(-) create mode 100644 Core/Inc/EEPROM.h create mode 100644 Core/Src/EEPROM.c diff --git a/Core/Inc/EEPROM.h b/Core/Inc/EEPROM.h new file mode 100644 index 0000000..d876a49 --- /dev/null +++ b/Core/Inc/EEPROM.h @@ -0,0 +1,41 @@ +#ifndef INC_EEPROM_H_ +#define INC_EEPROM_H_ + +#include "stm32f4xx_hal.h" +#include "stm32f4xx_hal_def.h" + +#define EEPROM_BASE_ADDR 0b1010000 +// Device address must be shifted left before being passed to the HAL +#define EEPROM_DEV_ADDR (EEPROM_BASE_ADDR << 1) +#define EEPROM_TIMEOUT 200 /* ms */ +#define EEPROM_READ_TRIES 5 + +#define EEPROM_ADDR_SLAVE_ID 0x000 + +typedef enum { EEPROM_OFF, EEPROM_READY, EEPROM_ERROR } EEPROM_State; +extern EEPROM_State eeprom_state; + +void eeprom_init(I2C_HandleTypeDef* handle); + +/** + * @brief Write a byte to the EEPROM. + * + * @param addr 9-bit address (1 bit page select + 8 bit address) + * @param data The byte to write + */ +HAL_StatusTypeDef eeprom_write(uint16_t addr, uint8_t data); +/** + * @brief Read a byte from the next address in the EEPROM. + * + * @param data 1-byte buffer into which the read byte is written. + */ +HAL_StatusTypeDef eeprom_read_curr(uint8_t* data); +/** + * @brief Read a byte from the EEPROM (random-access). + * + * @param addr 9-bit address (1 bit page select + 8 bit address) + * @param data 1-byte buffer into which the read byte is written. + */ +HAL_StatusTypeDef eeprom_read_random(uint16_t addr, uint8_t* data); + +#endif // INC_EEPROM_H_ diff --git a/Core/Inc/stm32f4xx_it.h b/Core/Inc/stm32f4xx_it.h index 01e23c3..bc45418 100644 --- a/Core/Inc/stm32f4xx_it.h +++ b/Core/Inc/stm32f4xx_it.h @@ -57,6 +57,7 @@ void PendSV_Handler(void); void SysTick_Handler(void); void CAN1_RX0_IRQHandler(void); void CAN1_RX1_IRQHandler(void); +void I2C1_EV_IRQHandler(void); void USART1_IRQHandler(void); void USART3_IRQHandler(void); void CAN2_RX0_IRQHandler(void); diff --git a/Core/Src/EEPROM.c b/Core/Src/EEPROM.c new file mode 100644 index 0000000..da8cf97 --- /dev/null +++ b/Core/Src/EEPROM.c @@ -0,0 +1,71 @@ +#include "EEPROM.h" + +#include "main.h" + +#include "stm32f4xx_hal_def.h" +#include "stm32f4xx_hal_i2c.h" + +EEPROM_State eeprom_state = EEPROM_OFF; + +I2C_HandleTypeDef* i2c; + +void eeprom_init(I2C_HandleTypeDef* handle) { + i2c = handle; + eeprom_state = EEPROM_READY; +} + +HAL_StatusTypeDef eeprom_write(uint16_t addr, uint8_t data) { + uint8_t page = (addr >> 8) & 0b1; + uint8_t mem_addr = addr & 0xFF; + // Address must be shifted left for the HAL + uint8_t dev_addr = EEPROM_DEV_ADDR | (page << 1); + + uint8_t msg[2] = {mem_addr, data}; + return HAL_I2C_Master_Transmit(i2c, dev_addr, msg, 2, EEPROM_TIMEOUT); +} + +HAL_StatusTypeDef eeprom_read_curr(uint8_t* data) { + return HAL_I2C_Master_Receive(i2c, EEPROM_DEV_ADDR, data, 1, EEPROM_TIMEOUT); +} + +HAL_StatusTypeDef eeprom_read_random(uint16_t addr, uint8_t* data) { + // This is basically an SMBus Read Byte, see + // https://www.kernel.org/doc/html/latest/i2c/smbus-protocol.html#smbus-read-byte + + uint8_t page = (addr >> 8) & 0b1; + uint8_t mem_addr = addr & 0xFF; + // Address must be shifted left for the HAL + uint8_t dev_addr = EEPROM_DEV_ADDR | (page << 1); + + HAL_StatusTypeDef status = HAL_I2C_Master_Seq_Transmit_IT( + i2c, dev_addr, &mem_addr, 1, I2C_FIRST_FRAME); + if (status != HAL_OK) { + return status; + } + + // Wait for write to be complete + while (HAL_I2C_GetState(i2c) != HAL_I2C_STATE_READY) { + } + + // Try up to EEPROM_READ_TRIES times to get an acknowledgement from the slave. + // If we don't abort and return the error. + for (int i = 0; i < EEPROM_READ_TRIES; i++) { + status = + HAL_I2C_Master_Seq_Receive_IT(i2c, dev_addr, data, 1, I2C_LAST_FRAME); + if (status == HAL_OK) { + break; + } else if (HAL_I2C_GetError(i2c) != HAL_I2C_ERROR_AF) { + // Not an acknowledge failure -> timeout, abort + break; + } + } + if (status != HAL_OK) { + return status; + } + + // Wait for read to be complete + while (HAL_I2C_GetState(i2c) != HAL_I2C_STATE_READY) { + } + + return HAL_OK; +} diff --git a/Core/Src/main.c b/Core/Src/main.c index 339a1e2..c4b6e45 100644 --- a/Core/Src/main.c +++ b/Core/Src/main.c @@ -22,6 +22,7 @@ /* Private includes ----------------------------------------------------------*/ /* USER CODE BEGIN Includes */ #include "BQ_Abstraction_Layer.h" +#include "EEPROM.h" #include "stm32f4xx_hal.h" #include "stm32f4xx_hal_gpio.h" @@ -139,6 +140,11 @@ int main(void) { HAL_GPIO_WritePin(DCDC_CTRL_GPIO_Port, DCDC_CTRL_Pin, GPIO_PIN_SET); HAL_Delay(100); afe_init(&huart2); + eeprom_init(&hi2c1); + uint8_t id; + if (eeprom_read_random(EEPROM_ADDR_SLAVE_ID, &id) == HAL_OK) { + HAL_GPIO_WritePin(STAT_LED4_GPIO_Port, STAT_LED4_Pin, GPIO_PIN_SET); + } /* USER CODE END 2 */ /* Infinite loop */ diff --git a/Core/Src/stm32f4xx_hal_msp.c b/Core/Src/stm32f4xx_hal_msp.c index d731174..dcb5876 100644 --- a/Core/Src/stm32f4xx_hal_msp.c +++ b/Core/Src/stm32f4xx_hal_msp.c @@ -246,6 +246,9 @@ void HAL_I2C_MspInit(I2C_HandleTypeDef* hi2c) /* Peripheral clock enable */ __HAL_RCC_I2C1_CLK_ENABLE(); + /* I2C1 interrupt Init */ + HAL_NVIC_SetPriority(I2C1_EV_IRQn, 0, 0); + HAL_NVIC_EnableIRQ(I2C1_EV_IRQn); /* USER CODE BEGIN I2C1_MspInit 1 */ /* USER CODE END I2C1_MspInit 1 */ @@ -277,6 +280,8 @@ void HAL_I2C_MspDeInit(I2C_HandleTypeDef* hi2c) HAL_GPIO_DeInit(GPIOB, GPIO_PIN_7); + /* I2C1 interrupt DeInit */ + HAL_NVIC_DisableIRQ(I2C1_EV_IRQn); /* USER CODE BEGIN I2C1_MspDeInit 1 */ /* USER CODE END I2C1_MspDeInit 1 */ diff --git a/Core/Src/stm32f4xx_it.c b/Core/Src/stm32f4xx_it.c index e74f093..9c5f27c 100644 --- a/Core/Src/stm32f4xx_it.c +++ b/Core/Src/stm32f4xx_it.c @@ -57,6 +57,7 @@ /* External variables --------------------------------------------------------*/ extern CAN_HandleTypeDef hcan1; extern CAN_HandleTypeDef hcan2; +extern I2C_HandleTypeDef hi2c1; extern UART_HandleTypeDef huart1; extern UART_HandleTypeDef huart3; /* USER CODE BEGIN EV */ @@ -228,6 +229,20 @@ void CAN1_RX1_IRQHandler(void) /* USER CODE END CAN1_RX1_IRQn 1 */ } +/** + * @brief This function handles I2C1 event interrupt. + */ +void I2C1_EV_IRQHandler(void) +{ + /* USER CODE BEGIN I2C1_EV_IRQn 0 */ + + /* USER CODE END I2C1_EV_IRQn 0 */ + HAL_I2C_EV_IRQHandler(&hi2c1); + /* USER CODE BEGIN I2C1_EV_IRQn 1 */ + + /* USER CODE END I2C1_EV_IRQn 1 */ +} + /** * @brief This function handles USART1 global interrupt. */ diff --git a/Makefile b/Makefile index ccc4791..7c8cf52 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ ########################################################################################################################## -# File automatically-generated by tool: [projectgenerator] version: [3.16.0] date: [Thu Jun 09 23:03:25 CEST 2022] +# File automatically-generated by tool: [projectgenerator] version: [3.16.0] date: [Sun Jun 12 16:56:47 CEST 2022] ########################################################################################################################## # ------------------------------------------------ diff --git a/STM32Make.make b/STM32Make.make index 33dbbaa..239b573 100644 --- a/STM32Make.make +++ b/STM32Make.make @@ -40,6 +40,7 @@ Core/Src/AMS_CAN.c \ Core/Src/BQ_Abstraction_Layer.c \ Core/Src/BQ_Communication.c \ Core/Src/BatteryManagement.c \ +Core/Src/EEPROM.c \ Core/Src/SoftI2C.c \ Core/Src/TMP144.c \ Core/Src/main.c \ diff --git a/ams-slave.ioc b/ams-slave.ioc index dacb60d..0141ebf 100644 --- a/ams-slave.ioc +++ b/ams-slave.ioc @@ -73,6 +73,7 @@ NVIC.CAN2_SCE_IRQn=true\:0\:0\:false\:false\:true\:true\:true\:true NVIC.DebugMonitor_IRQn=true\:1\:0\:true\:false\:true\:false\:false\:true NVIC.ForceEnableDMAVector=true NVIC.HardFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:true +NVIC.I2C1_EV_IRQn=true\:0\:0\:false\:false\:true\:true\:true\:true NVIC.MemoryManagement_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:true NVIC.NonMaskableInt_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:true NVIC.PendSV_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:true