Ajout FishPeper

This commit is contained in:
Serge NOEL
2026-04-21 12:19:15 +02:00
parent 6744da3f88
commit 0c361a2440
2160 changed files with 589301 additions and 1 deletions

View File

@@ -0,0 +1,485 @@
/*
Copyright 2017 fishpepper <AT> gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program 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 this program. If not, see <http:// www.gnu.org/licenses/>.
author: fishpepper <AT> gmail.com
*/
#include "hal_storage.h"
#include "delay.h"
#include "debug.h"
#include "timeout.h"
#include "stm32f10x_i2c.h"
#include "stm32f10x_rcc.h"
#define HAL_STORAGE_I2C_DEBUG 1
#define EEPROM_I2C_TIMEOUT 20
#define EEPROM_I2C_FLAG_TIMEOUT 10
void hal_storage_init(void) {
hal_storage_init_i2c();
}
void hal_storage_write(uint8_t *buffer, uint16_t len) {
// verify write size
if (!hal_storage_check_len(len)) return;
// disable write protection
hal_storage_wp_disable();
delay_ms(1);
// execute write
if (!hal_storage_i2c_write_buffer(0, buffer, (uint8_t)len)) {
debug("hal_storage: ERROR! failed to write buffer\n");
debug_flush();
}
// re-enable write protection
delay_ms(1);
hal_storage_wp_enable();
}
void hal_storage_read(uint8_t *storage_ptr, uint16_t len) {
// verify read size
if (!hal_storage_check_len(len)) return;
if (!hal_storage_i2c_read_buffer(0, storage_ptr, (uint8_t)len)) {
debug("hal_storage: ERROR! failed to read buffer\n");
debug_flush();
}
}
static void hal_storage_init_i2c(void) {
// disable i2c:
I2C_Cmd(EEPROM_I2C, DISABLE);
I2C_DeInit(EEPROM_I2C);
hal_storage_init_i2c_rcc();
hal_storage_init_i2c_gpio();
}
static void hal_storage_init_i2c_rcc(void) {
// peripheral clock for i2c
RCC_APBxPeriphClockCmd(EEPROM_I2C_CLK_RCC, EEPROM_I2C_CLK, ENABLE);
// gpio clock
RCC_APBxPeriphClockCmd(EEPROM_GPIO_CLK_RCC, EEPROM_GPIO_CLK, ENABLE);
}
static void hal_storage_init_i2c_mode(void) {
I2C_InitTypeDef i2c_init;
i2c_init.I2C_Mode = I2C_Mode_I2C;
i2c_init.I2C_DutyCycle = I2C_DutyCycle_2;
i2c_init.I2C_OwnAddress1 = EEPROM_I2C_ADDRESS;
i2c_init.I2C_Ack = I2C_Ack_Enable;
i2c_init.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
i2c_init.I2C_ClockSpeed = 200000;
// apply I2C configuration
I2C_Init(EEPROM_I2C, &i2c_init);
// enable i2c
I2C_Cmd(EEPROM_I2C, ENABLE);
}
static void hal_storage_init_i2c_gpio(void) {
GPIO_InitTypeDef gpio_init;
uint8_t i;
// gpio init:
// reset i2c bus by setting clk as output and sending manual clock pulses
gpio_init.GPIO_Pin = EEPROM_I2C_SCL_PIN;
gpio_init.GPIO_Mode = GPIO_Mode_Out_OD;
gpio_init.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(EEPROM_GPIO, &gpio_init);
gpio_init.GPIO_Pin = EEPROM_I2C_SDA_PIN;
gpio_init.GPIO_Mode = GPIO_Mode_IN_FLOATING;
gpio_init.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(EEPROM_GPIO, &gpio_init);
if (1) {
debug("hal_storage: freeing i2c bus with clock train\n");
debug_flush();
// send 100khz clock train for some 100ms
timeout_set(100);
while (!timeout_timed_out()) {
if (GPIO_ReadInputDataBit(EEPROM_GPIO, EEPROM_I2C_SDA_PIN) == 1) {
debug("hal_storage: i2c free again\n");
break;
}
EEPROM_GPIO->BSRR = EEPROM_I2C_SCL_PIN;
delay_us(10);
EEPROM_GPIO->BRR = EEPROM_I2C_SCL_PIN;
delay_us(10);
}
// send stop condition:
gpio_init.GPIO_Pin = EEPROM_I2C_SDA_PIN;
gpio_init.GPIO_Mode = GPIO_Mode_Out_OD;
gpio_init.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(EEPROM_GPIO, &gpio_init);
// clock is low
EEPROM_GPIO->BRR = EEPROM_I2C_SCL_PIN;
delay_us(10);
// sda = lo
EEPROM_GPIO->BRR = EEPROM_I2C_SDA_PIN;
delay_us(10);
// clock goes high
EEPROM_GPIO->BSRR = EEPROM_I2C_SCL_PIN;
delay_us(10);
}
// init mode before setting to AF
hal_storage_init_i2c_mode();
// SDA & SCL
gpio_init.GPIO_Pin = EEPROM_I2C_SDA_PIN | EEPROM_I2C_SCL_PIN;
gpio_init.GPIO_Mode = GPIO_Mode_AF_OD;
gpio_init.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(EEPROM_GPIO, &gpio_init);
// WP = write protection
gpio_init.GPIO_Pin = EEPROM_WP_PIN;
gpio_init.GPIO_Mode = GPIO_Mode_Out_PP;
gpio_init.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(EEPROM_GPIO, &gpio_init);
// WP = HI = protected
hal_storage_wp_enable();
}
static uint32_t hal_storage_check_len(uint16_t len) {
if (len > 255) {
debug("hal_storage: ERROR, invalid data len ");
debug_put_uint16(len);
debug(" (max is 255)!\n");
debug_flush();
// invalid
return 0;
} else {
// safe
return 1;
}
}
static uint32_t hal_storage_i2c_read_buffer(uint16_t address, uint8_t *buffer, uint8_t len) {
if (HAL_STORAGE_I2C_DEBUG) {
debug("hal_storage: i2c read_buffer(0x");
debug_put_hex8(address>>8);
debug_put_hex8(address&0xFF);
debug(", ..., ");
debug_put_uint16(len);
debug(")\n");
debug_flush();
}
timeout_set(EEPROM_I2C_TIMEOUT);
while (I2C_GetFlagStatus(EEPROM_I2C, I2C_FLAG_BUSY)) {
if (timeout_timed_out()) {
debug("hal_i2c: bus busy... timeout!\n");
return 0;
}
}
// send start
I2C_GenerateSTART(EEPROM_I2C, ENABLE);
// set on EV5 and clear it (cleared by reading SR1 then writing to DR)
timeout_set(EEPROM_I2C_FLAG_TIMEOUT);
while (!I2C_CheckEvent(EEPROM_I2C, I2C_EVENT_MASTER_MODE_SELECT)) {
if (timeout_timed_out()) {
debug("hal_i2c: master flag error... timeout!\n");
return 0;
}
}
// send EEPROM address for write
I2C_Send7bitAddress(EEPROM_I2C, EEPROM_I2C_ADDRESS, I2C_Direction_Transmitter);
// test on EV6 and clear it
timeout_set(EEPROM_I2C_FLAG_TIMEOUT);
while (!I2C_CheckEvent(EEPROM_I2C, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)) {
if (timeout_timed_out()) {
debug("hal_i2c: transmitter flag error... timeout!\n");
return 0;
}
}
// send the EEPROM's internal address to read from: Only one byte address
I2C_SendData(EEPROM_I2C, address);
// test on EV8 and clear it
timeout_set(EEPROM_I2C_FLAG_TIMEOUT);
while (!I2C_GetFlagStatus(EEPROM_I2C, I2C_FLAG_BTF) == RESET) {
if (timeout_timed_out()) {
debug("hal_i2c: btf flag error... timeout!\n");
return 0;
}
}
// send START condition a second time
I2C_GenerateSTART(EEPROM_I2C, ENABLE);
// set on EV5 and clear it (cleared by reading SR1 then writing to DR)
timeout_set(EEPROM_I2C_FLAG_TIMEOUT);
while (!I2C_CheckEvent(EEPROM_I2C, I2C_EVENT_MASTER_MODE_SELECT)) {
if (timeout_timed_out()) {
debug("hal_i2c: master flag error... timeout!\n");
return 0;
}
}
// send address (READ)
I2C_Send7bitAddress(EEPROM_I2C, EEPROM_I2C_ADDRESS, I2C_Direction_Receiver);
// test on EV6 and clear it
timeout_set(EEPROM_I2C_FLAG_TIMEOUT);
while (!I2C_CheckEvent(EEPROM_I2C, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED)) {
if (timeout_timed_out()) {
debug("hal_i2c: receiver flag error... timeout!\n");
return 0;
}
}
if (HAL_STORAGE_I2C_DEBUG) {
debug("hal_storage: reading ");
debug_put_uint8(len);
debug("bytes: ");
debug_flush();
}
// do not use dma etc, we do not need highspeed. do polling:
uint16_t i;
for (i = 0; i < len; i++) {
// wait on ADDR flag to be set (ADDR is still not cleared at this level)
timeout_set(EEPROM_I2C_FLAG_TIMEOUT);
/* Test on EV7 and clear it */
while (!I2C_CheckEvent(EEPROM_I2C, I2C_EVENT_MASTER_BYTE_RECEIVED)) {
if (timeout_timed_out()) {
debug("hal_i2c: byte rx error... timeout!\n");
return 0;
}
}
// read byte received:
buffer[i] = I2C_ReceiveData(EEPROM_I2C);
if (HAL_STORAGE_I2C_DEBUG) {
debug_put_hex8(buffer[i]);
debug_putc(' ');
debug_flush();
}
if (i == (len-1)) {
// last byte? -> NACK
I2C_AcknowledgeConfig(EEPROM_I2C, DISABLE);
} else {
// more bytes -> ACK
I2C_AcknowledgeConfig(EEPROM_I2C, ENABLE);
}
// wait for read to finish
timeout_set(EEPROM_I2C_FLAG_TIMEOUT*100);
while (!I2C_CheckEvent(EEPROM_I2C, I2C_EVENT_SLAVE_BYTE_RECEIVED)) {
// while (I2C_GetFlagStatus(EEPROM_I2C, I2C_FLAG_RXNE) == RESET) {
if (timeout_timed_out()) {
debug("hal_i2c: read error... timeout!\n");
return 0;
}
}
}
// stop transmission
// clear ADDR register by reading SR1 then SR2 register (SR1 has already been read) */
(void)EEPROM_I2C->SR2;
// send STOP Condition
I2C_GenerateSTOP(EEPROM_I2C, ENABLE);
if (HAL_STORAGE_I2C_DEBUG) {
debug(". done.\n");
debug_flush();
}
// wait to make sure that STOP control bit has been cleared
timeout_set(EEPROM_I2C_FLAG_TIMEOUT);
while (EEPROM_I2C->CR1 & I2C_CR1_STOP) {
if (timeout_timed_out()) {
debug("hal_i2c: stop flag error... timeout!\n");
return 0;
}
}
// re-enable Acknowledgement to be ready for another reception
I2C_AcknowledgeConfig(EEPROM_I2C, ENABLE);
if (HAL_STORAGE_I2C_DEBUG) {
debug("hal_storage: read done\n");
debug_flush();
}
return 1;
}
static uint32_t hal_storage_i2c_write_buffer(uint8_t address, uint8_t *buffer, uint8_t len) {
if (HAL_STORAGE_I2C_DEBUG) {
debug("hal_storage: i2c write_buffer(0x");
debug_put_hex8(address>>8);
debug_put_hex8(address&0xFF);
debug(", ..., ");
debug_put_uint16(len);
debug(")\n");
debug_flush();
}
uint8_t i;
// check for out of bound condition
uint16_t last_byte = (uint16_t)address + (uint16_t) len;
if (last_byte > 255) {
debug("hal_storage: ERROR write request invalid. out of memory!\n");
debug_flush();
return 0;
}
// write data
for (i = 0; i < len; i++) {
if (!hal_storage_i2c_write_byte(address + i, buffer[i])) {
return 0;
}
}
return 1;
}
// single byte write is slow and ugly but will do
// we only use this once during binding...
static uint32_t hal_storage_i2c_write_byte(uint8_t address, uint8_t data) {
if (HAL_STORAGE_I2C_DEBUG) {
debug("hal_storage: i2c write_byte(0x");
debug_put_hex8(address>>8);
debug_put_hex8(address&0xFF);
debug(", 0x");
debug_put_hex8(data);
debug(")\n");
debug_flush();
}
timeout_set(EEPROM_I2C_TIMEOUT);
while (I2C_GetFlagStatus(EEPROM_I2C, I2C_FLAG_BUSY)) {
if (timeout_timed_out()) {
debug("hal_i2c: bus busy... timeout!\n");
return 0;
}
}
// send start
I2C_GenerateSTART(EEPROM_I2C, ENABLE);
// set on EV5 and clear it (cleared by reading SR1 then writing to DR)
timeout_set(EEPROM_I2C_FLAG_TIMEOUT);
while (!I2C_CheckEvent(EEPROM_I2C, I2C_EVENT_MASTER_MODE_SELECT)) {
if (timeout_timed_out()) {
debug("hal_i2c: master flag error... timeout!\n");
return 0;
}
}
// send EEPROM address for write
I2C_Send7bitAddress(EEPROM_I2C, EEPROM_I2C_ADDRESS, I2C_Direction_Transmitter);
// test on EV6 and clear it
timeout_set(EEPROM_I2C_FLAG_TIMEOUT);
while (!I2C_CheckEvent(EEPROM_I2C, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)) {
if (timeout_timed_out()) {
debug("hal_i2c: transmitter flag error... timeout!\n");
return 0;
}
}
// send the EEPROM's internal address to write to
I2C_SendData(EEPROM_I2C, address);
// test on EV8 and clear it
timeout_set(EEPROM_I2C_FLAG_TIMEOUT);
while (!I2C_CheckEvent(EEPROM_I2C, I2C_EVENT_MASTER_BYTE_TRANSMITTED)) {
if (timeout_timed_out()) {
debug("hal_i2c: address tx error... timeout!\n");
return 0;
}
}
// send data byte
I2C_SendData(EEPROM_I2C, data);
// test on EV8 and clear it
timeout_set(EEPROM_I2C_FLAG_TIMEOUT);
while (!I2C_CheckEvent(EEPROM_I2C, I2C_EVENT_MASTER_BYTE_TRANSMITTED)) {
if (timeout_timed_out()) {
debug("hal_i2c: data tx error... timeout!\n");
return 0;
}
}
// stop transmission
// clear ADDR register by reading SR1 then SR2 register (SR1 has already been read) */
(void)EEPROM_I2C->SR2;
// send STOP Condition
I2C_GenerateSTOP(EEPROM_I2C, ENABLE);
// wait to make sure that STOP control bit has been cleared
timeout_set(EEPROM_I2C_FLAG_TIMEOUT);
while (EEPROM_I2C->CR1 & I2C_CR1_STOP) {
if (timeout_timed_out()) {
debug("hal_i2c: stop flag error... timeout!\n");
return 0;
}
}
// wait for write cycle time (5ms)
delay_ms(5+1);
if (HAL_STORAGE_I2C_DEBUG) {
debug("hal_storage: write done\n");
debug_flush();
}
return 1;
}