mirror of
https://github.com/Polprzewodnikowy/SummerCart64.git
synced 2024-11-22 05:59:15 +01:00
I2C lockup prevention
This commit is contained in:
parent
3683259b06
commit
838082f44f
@ -4,8 +4,7 @@
|
||||
#include "hw.h"
|
||||
|
||||
|
||||
#define CPU_FREQ (64000000UL)
|
||||
#define UART_BAUD (115200UL)
|
||||
#define CPU_FREQ (64000000UL)
|
||||
|
||||
|
||||
void hw_set_vector_table (uint32_t offset) {
|
||||
@ -42,17 +41,62 @@ static void hw_clock_init (void) {
|
||||
}
|
||||
|
||||
|
||||
static void hw_delay_init (void) {
|
||||
SysTick->LOAD = (((CPU_FREQ / 1000)) - 1);
|
||||
SysTick->VAL = 0;
|
||||
SysTick->CTRL = (SysTick_CTRL_CLKSOURCE_Msk | SysTick_CTRL_ENABLE_Msk);
|
||||
#define TIMEOUT_US_PER_TICK (10)
|
||||
|
||||
static void hw_timeout_init (void) {
|
||||
RCC->APBENR1 |= RCC_APBENR1_DBGEN;
|
||||
DBG->APBFZ2 |= DBG_APB_FZ2_DBG_TIM17_STOP;
|
||||
|
||||
RCC->APBENR2 |= RCC_APBENR2_TIM17EN;
|
||||
|
||||
TIM17->CR1 = TIM_CR1_OPM;
|
||||
TIM17->PSC = (((CPU_FREQ / 1000 / 1000) * TIMEOUT_US_PER_TICK) - 1);
|
||||
TIM17->EGR = TIM_EGR_UG;
|
||||
}
|
||||
|
||||
void hw_delay_ms (uint32_t ms) {
|
||||
SysTick->VAL = 0;
|
||||
for (uint32_t i = 0; i < ms; i++) {
|
||||
while (!(SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk));
|
||||
static void hw_timeout_start (void) {
|
||||
TIM17->CR1 &= ~(TIM_CR1_CEN);
|
||||
TIM17->CNT = 0;
|
||||
TIM17->CR1 |= TIM_CR1_CEN;
|
||||
}
|
||||
|
||||
static bool hw_timeout_occured (uint32_t timeout_us) {
|
||||
uint16_t count = TIM17->CNT;
|
||||
|
||||
uint32_t adjusted_timeout = ((timeout_us + (TIMEOUT_US_PER_TICK - 1)) / TIMEOUT_US_PER_TICK);
|
||||
|
||||
if ((count >= adjusted_timeout) || (count == 0xFFFF)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
#define DELAY_MS_PER_TICK (1)
|
||||
|
||||
static void hw_delay_init (void) {
|
||||
RCC->APBENR1 |= RCC_APBENR1_DBGEN;
|
||||
DBG->APBFZ2 |= DBG_APB_FZ2_DBG_TIM16_STOP;
|
||||
|
||||
RCC->APBENR2 |= RCC_APBENR2_TIM16EN;
|
||||
|
||||
TIM16->CR1 = TIM_CR1_OPM;
|
||||
TIM16->PSC = (((CPU_FREQ / 1000) * DELAY_MS_PER_TICK) - 1);
|
||||
TIM16->EGR = TIM_EGR_UG;
|
||||
}
|
||||
|
||||
void hw_delay_ms (uint32_t delay_ms) {
|
||||
TIM16->CR1 &= ~(TIM_CR1_CEN);
|
||||
TIM16->CNT = 0;
|
||||
TIM16->CR1 |= TIM_CR1_CEN;
|
||||
|
||||
uint32_t adjusted_delay = ((delay_ms + (DELAY_MS_PER_TICK - 1)) / DELAY_MS_PER_TICK);
|
||||
|
||||
uint16_t count;
|
||||
do {
|
||||
count = TIM16->CNT;
|
||||
} while ((count < adjusted_delay) && (count != 0xFFFF));
|
||||
}
|
||||
|
||||
|
||||
@ -114,7 +158,7 @@ static void hw_gpio_init (gpio_id_t id, gpio_mode_t mode, gpio_ot_t ot, gpio_osp
|
||||
uint8_t pin = (id & 0x0F);
|
||||
uint8_t afr = ((pin < 8) ? 0 : 1);
|
||||
|
||||
RCC->IOPENR |= RCC_IOPENR_GPIOAEN | RCC_IOPENR_GPIOBEN;
|
||||
RCC->IOPENR |= (RCC_IOPENR_GPIOAEN | RCC_IOPENR_GPIOBEN);
|
||||
|
||||
tmp.MODER = (gpio->MODER & ~(GPIO_MODER_MODE0_Msk << (pin * 2)));
|
||||
tmp.OTYPER = (gpio->OTYPER & ~(GPIO_OTYPER_OT0_Msk << pin));
|
||||
@ -150,6 +194,8 @@ void hw_gpio_reset (gpio_id_t id) {
|
||||
}
|
||||
|
||||
|
||||
#define UART_BAUD (115200UL)
|
||||
|
||||
static void hw_uart_init (void) {
|
||||
RCC->APBENR2 |= (RCC_APBENR2_USART1EN | RCC_APBENR2_SYSCFGEN);
|
||||
|
||||
@ -158,9 +204,9 @@ static void hw_uart_init (void) {
|
||||
hw_gpio_init(GPIO_ID_UART_TX, GPIO_ALT, GPIO_PP, GPIO_SPEED_LOW, GPIO_PULL_UP, GPIO_AF_1, 0);
|
||||
hw_gpio_init(GPIO_ID_UART_RX, GPIO_ALT, GPIO_PP, GPIO_SPEED_LOW, GPIO_PULL_UP, GPIO_AF_1, 0);
|
||||
|
||||
USART1->BRR = CPU_FREQ / UART_BAUD;
|
||||
USART1->RQR = USART_RQR_TXFRQ | USART_RQR_RXFRQ;
|
||||
USART1->CR1 = USART_CR1_FIFOEN | USART_CR1_M0 | USART_CR1_PCE | USART_CR1_TE | USART_CR1_RE | USART_CR1_UE;
|
||||
USART1->BRR = (CPU_FREQ / UART_BAUD);
|
||||
USART1->RQR = (USART_RQR_TXFRQ | USART_RQR_RXFRQ);
|
||||
USART1->CR1 = (USART_CR1_FIFOEN | USART_CR1_M0 | USART_CR1_PCE | USART_CR1_TE | USART_CR1_RE | USART_CR1_UE);
|
||||
}
|
||||
|
||||
void hw_uart_read (uint8_t *data, int length) {
|
||||
@ -259,26 +305,35 @@ void hw_spi_tx (uint8_t *data, int length) {
|
||||
}
|
||||
|
||||
|
||||
#define I2C_TIMEOUT_US_BUSY (1000)
|
||||
#define I2C_TIMEOUT_US_PER_BYTE (100)
|
||||
|
||||
static void hw_i2c_init (void) {
|
||||
RCC->APBENR1 |= RCC_APBENR1_I2C1EN;
|
||||
|
||||
I2C1->CR1 &= ~(I2C_CR1_PE);
|
||||
I2C1->CR1 = 0;
|
||||
|
||||
hw_gpio_init(GPIO_ID_I2C_SCL, GPIO_ALT, GPIO_OD, GPIO_SPEED_VLOW, GPIO_PULL_NONE, GPIO_AF_6, 0);
|
||||
hw_gpio_init(GPIO_ID_I2C_SDA, GPIO_ALT, GPIO_OD, GPIO_SPEED_VLOW, GPIO_PULL_NONE, GPIO_AF_6, 0);
|
||||
|
||||
while (true) {
|
||||
if (hw_gpio_get(GPIO_ID_I2C_SCL) && hw_gpio_get(GPIO_ID_I2C_SDA)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (!(hw_gpio_get(GPIO_ID_I2C_SCL) && hw_gpio_get(GPIO_ID_I2C_SDA)));
|
||||
|
||||
I2C1->TIMINGR = 0x10901032UL;
|
||||
I2C1->CR1 |= I2C_CR1_PE;
|
||||
}
|
||||
|
||||
i2c_err_t hw_i2c_trx (uint8_t address, uint8_t *tx_data, uint8_t tx_length, uint8_t *rx_data, uint8_t rx_length) {
|
||||
while (I2C1->ISR & I2C_ISR_BUSY);
|
||||
hw_timeout_start();
|
||||
|
||||
while (I2C1->ISR & I2C_ISR_BUSY) {
|
||||
if (hw_timeout_occured(I2C_TIMEOUT_US_BUSY)) {
|
||||
return I2C_ERR_BUSY;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t timeout = ((tx_length + rx_length) * I2C_TIMEOUT_US_PER_BYTE);
|
||||
|
||||
hw_timeout_start();
|
||||
|
||||
if (tx_length > 0) {
|
||||
I2C1->ICR = I2C_ICR_NACKCF;
|
||||
@ -302,14 +357,20 @@ i2c_err_t hw_i2c_trx (uint8_t address, uint8_t *tx_data, uint8_t tx_length, uint
|
||||
if (isr & I2C_ISR_NACKF) {
|
||||
return I2C_ERR_NACK;
|
||||
}
|
||||
|
||||
if (hw_timeout_occured(timeout)) {
|
||||
return I2C_ERR_TIMEOUT;
|
||||
}
|
||||
}
|
||||
|
||||
if (rx_length == 0) {
|
||||
return I2C_OK;
|
||||
}
|
||||
|
||||
if (left == 0) {
|
||||
while (!(I2C1->ISR & I2C_ISR_TC));
|
||||
while (!(I2C1->ISR & I2C_ISR_TC)) {
|
||||
if (hw_timeout_occured(timeout)) {
|
||||
return I2C_ERR_TIMEOUT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -331,6 +392,10 @@ i2c_err_t hw_i2c_trx (uint8_t address, uint8_t *tx_data, uint8_t tx_length, uint
|
||||
*rx_data++ = I2C1->RXDR;
|
||||
left -= 1;
|
||||
}
|
||||
|
||||
if (hw_timeout_occured(timeout)) {
|
||||
return I2C_ERR_TIMEOUT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -392,7 +457,7 @@ void hw_flash_program (uint32_t offset, hw_flash_t value) {
|
||||
|
||||
void hw_reset (loader_parameters_t *parameters) {
|
||||
if (parameters != NULL) {
|
||||
RCC->APBENR1 |= RCC_APBENR1_PWREN | RCC_APBENR1_RTCAPBEN;
|
||||
RCC->APBENR1 |= (RCC_APBENR1_PWREN | RCC_APBENR1_RTCAPBEN);
|
||||
PWR->CR1 |= PWR_CR1_DBP;
|
||||
TAMP->BKP0R = parameters->magic;
|
||||
TAMP->BKP1R = parameters->flags;
|
||||
@ -407,7 +472,7 @@ void hw_reset (loader_parameters_t *parameters) {
|
||||
|
||||
|
||||
void hw_loader_get_parameters (loader_parameters_t *parameters) {
|
||||
RCC->APBENR1 |= RCC_APBENR1_PWREN | RCC_APBENR1_RTCAPBEN;
|
||||
RCC->APBENR1 |= (RCC_APBENR1_PWREN | RCC_APBENR1_RTCAPBEN);
|
||||
parameters->magic = TAMP->BKP0R;
|
||||
parameters->flags = TAMP->BKP1R;
|
||||
parameters->mcu_address = TAMP->BKP2R;
|
||||
@ -440,6 +505,7 @@ static void hw_misc_init (void) {
|
||||
|
||||
void hw_primer_init (void) {
|
||||
hw_clock_init();
|
||||
hw_timeout_init();
|
||||
hw_delay_init();
|
||||
hw_led_init();
|
||||
hw_uart_init();
|
||||
@ -450,6 +516,7 @@ void hw_primer_init (void) {
|
||||
|
||||
void hw_loader_init (void) {
|
||||
hw_clock_init();
|
||||
hw_timeout_init();
|
||||
hw_delay_init();
|
||||
hw_led_init();
|
||||
hw_spi_init();
|
||||
@ -457,10 +524,12 @@ void hw_loader_init (void) {
|
||||
|
||||
void hw_app_init (void) {
|
||||
hw_clock_init();
|
||||
hw_timeout_init();
|
||||
hw_delay_init();
|
||||
hw_led_init();
|
||||
hw_misc_init();
|
||||
hw_uart_init();
|
||||
hw_spi_init();
|
||||
hw_i2c_init();
|
||||
hw_crc32_init();
|
||||
hw_misc_init();
|
||||
}
|
||||
|
@ -27,6 +27,8 @@ typedef enum {
|
||||
|
||||
typedef enum {
|
||||
I2C_OK,
|
||||
I2C_ERR_BUSY,
|
||||
I2C_ERR_TIMEOUT,
|
||||
I2C_ERR_NACK,
|
||||
} i2c_err_t;
|
||||
|
||||
|
@ -1,4 +1,3 @@
|
||||
#include <string.h>
|
||||
#include "fpga.h"
|
||||
#include "hw.h"
|
||||
#include "led.h"
|
||||
@ -36,10 +35,10 @@ static rtc_time_t rtc_time = {
|
||||
.second = 0x00,
|
||||
.minute = 0x00,
|
||||
.hour = 0x12,
|
||||
.weekday = 0x02,
|
||||
.weekday = 0x01,
|
||||
.day = 0x01,
|
||||
.month = 0x03,
|
||||
.year = 0x22
|
||||
.month = 0x01,
|
||||
.year = 0x24
|
||||
};
|
||||
static bool rtc_time_pending = false;
|
||||
|
||||
@ -62,22 +61,29 @@ static const uint8_t rtc_regs_bit_mask[7] = {
|
||||
};
|
||||
|
||||
|
||||
static void rtc_read (uint8_t address, uint8_t *data, uint8_t length) {
|
||||
uint8_t tmp = address;
|
||||
if (hw_i2c_trx(RTC_I2C_ADDRESS, &tmp, 1, data, length) != I2C_OK) {
|
||||
static bool rtc_read (uint8_t address, uint8_t *data, uint8_t length) {
|
||||
if (hw_i2c_trx(RTC_I2C_ADDRESS, &address, 1, data, length) != I2C_OK) {
|
||||
led_blink_error(LED_ERROR_RTC);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void rtc_write (uint8_t address, uint8_t *data, uint8_t length) {
|
||||
uint8_t tmp[16];
|
||||
tmp[0] = address;
|
||||
static bool rtc_write (uint8_t address, uint8_t *data, uint8_t length) {
|
||||
uint8_t buffer[16];
|
||||
buffer[0] = address;
|
||||
|
||||
for (int i = 0; i < length; i++) {
|
||||
tmp[i + 1] = data[i];
|
||||
buffer[i + 1] = data[i];
|
||||
}
|
||||
if (hw_i2c_trx(RTC_I2C_ADDRESS, tmp, length + 1, NULL, 0) != I2C_OK) {
|
||||
|
||||
if (hw_i2c_trx(RTC_I2C_ADDRESS, buffer, length + 1, NULL, 0) != I2C_OK) {
|
||||
led_blink_error(LED_ERROR_RTC);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void rtc_sanitize_time (uint8_t *regs) {
|
||||
@ -91,15 +97,15 @@ static void rtc_osc_stop (void) {
|
||||
|
||||
rtc_write(RTC_ADDRESS_RTCSEC, &tmp, 1);
|
||||
|
||||
do {
|
||||
rtc_read(RTC_ADDRESS_RTCWKDAY, &tmp, 1);
|
||||
} while (tmp & RTC_RTCWKDAY_OSCRUN);
|
||||
while ((!rtc_read(RTC_ADDRESS_RTCWKDAY, &tmp, 1)) && (tmp & RTC_RTCWKDAY_OSCRUN));
|
||||
}
|
||||
|
||||
static void rtc_read_time (void) {
|
||||
uint8_t regs[7];
|
||||
|
||||
rtc_read(RTC_ADDRESS_RTCSEC, regs, 7);
|
||||
if (rtc_read(RTC_ADDRESS_RTCSEC, regs, 7)) {
|
||||
return;
|
||||
}
|
||||
|
||||
rtc_sanitize_time(regs);
|
||||
|
||||
@ -198,7 +204,10 @@ void rtc_init (void) {
|
||||
uint8_t buffer[4];
|
||||
uint32_t settings_version;
|
||||
|
||||
memset(buffer, 0, 4);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
buffer[i] = 0;
|
||||
}
|
||||
|
||||
rtc_read(RTC_ADDRESS_SRAM_MAGIC, buffer, 4);
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
@ -211,7 +220,6 @@ void rtc_init (void) {
|
||||
if (uninitialized) {
|
||||
buffer[0] = 0;
|
||||
rtc_write(RTC_ADDRESS_SRAM_MAGIC, (uint8_t *) (magic), 4);
|
||||
rtc_write(RTC_ADDRESS_CONTROL, buffer, 1);
|
||||
rtc_write(RTC_ADDRESS_OSCTRIM, buffer, 1);
|
||||
rtc_write_time();
|
||||
rtc_write_region();
|
||||
|
Loading…
Reference in New Issue
Block a user