removed task subsystem + huge cleanup

This commit is contained in:
Mateusz Faderewski 2024-01-13 07:48:42 +01:00
parent f7eb6a73b4
commit 7d6e2bc5ee
42 changed files with 781 additions and 1193 deletions

View File

@ -382,7 +382,7 @@ module n64_si (
4'd1: {rtc_time_wp, rtc_backup_wp} <= rx_byte_data[1:0];
4'd2: begin
rtc_stopped <= rx_byte_data[2:1];
if (rx_byte_data[2:1] == 2'b00) begin
if ((|rtc_stopped) && (rx_byte_data[2:1] == 2'b00)) begin
n64_scb.rtc_pending <= 1'b1;
end
end

View File

@ -14,14 +14,12 @@ SRC_FILES = \
flash.c \
flashram.c \
fpga.c \
gvr.c \
hw.c \
isv.c \
lcmxo2.c \
led.c \
rtc.c \
sd.c \
task.c \
timer.c \
update.c \
usb.c \

View File

@ -1,34 +1,46 @@
#include "app.h"
#include "gvr.h"
#include "button.h"
#include "cfg.h"
#include "cic.h"
#include "dd.h"
#include "flashram.h"
#include "fpga.h"
#include "hw.h"
#include "led.h"
#include "isv.h"
#include "rtc.h"
#include "task.h"
#include "sd.h"
#include "timer.h"
#include "usb.h"
#include "writeback.h"
#define RTC_STACK_SIZE (256)
#define LED_STACK_SIZE (256)
#define GVR_STACK_SIZE (2048)
uint8_t rtc_stack[RTC_STACK_SIZE] __attribute__((aligned(8)));
uint8_t led_stack[LED_STACK_SIZE] __attribute__((aligned(8)));
uint8_t gvr_stack[GVR_STACK_SIZE] __attribute__((aligned(8)));
void app_get_stack_usage (uint32_t *usage) {
*usage++ = 0;
*usage++ = task_get_stack_usage(rtc_stack, RTC_STACK_SIZE);
*usage++ = task_get_stack_usage(led_stack, LED_STACK_SIZE);
*usage++ = task_get_stack_usage(gvr_stack, GVR_STACK_SIZE);
}
void app (void) {
hw_init();
hw_app_init();
task_create(TASK_ID_RTC, rtc_task, rtc_stack, RTC_STACK_SIZE);
task_create(TASK_ID_LED, led_task, led_stack, LED_STACK_SIZE);
task_create(TASK_ID_GVR, gvr_task, gvr_stack, GVR_STACK_SIZE);
timer_init();
rtc_init();
task_scheduler_start();
while (fpga_id_get() != FPGA_ID);
button_init();
cfg_init();
cic_init();
dd_init();
flashram_init();
isv_init();
sd_init();
usb_init();
writeback_init();
while (1) {
button_process();
cfg_process();
cic_process();
dd_process();
flashram_process();
isv_process();
rtc_process();
sd_process();
usb_process();
writeback_process();
}
}

View File

@ -1,11 +0,0 @@
#ifndef APP_H__
#define APP_H__
#include <stdint.h>
void app_get_stack_usage (uint32_t *usage);
#endif

View File

@ -39,6 +39,7 @@ button_mode_t button_get_mode (void) {
return p.mode;
}
void button_init (void) {
p.counter = 0;
p.state = false;
@ -46,9 +47,12 @@ void button_init (void) {
p.trigger = false;
}
void button_process (void) {
usb_tx_info_t packet_info;
uint32_t status = fpga_reg_get(REG_CFG_SCR);
if (status & CFG_SCR_BUTTON_STATE) {
if (p.counter < BUTTON_COUNTER_TRIGGER_ON) {
p.counter += 1;
@ -58,13 +62,16 @@ void button_process (void) {
p.counter -= 1;
}
}
if (!p.state && p.counter == BUTTON_COUNTER_TRIGGER_ON) {
p.state = true;
p.trigger = true;
}
if (p.state && p.counter == BUTTON_COUNTER_TRIGGER_OFF) {
p.state = false;
}
if (p.trigger) {
switch (p.mode) {
case BUTTON_MODE_N64_IRQ:

View File

@ -16,7 +16,9 @@ typedef enum {
bool button_get_state (void);
bool button_set_mode (button_mode_t mode);
button_mode_t button_get_mode (void);
void button_init (void);
void button_process (void);

View File

@ -373,11 +373,11 @@ bool cfg_update (uint32_t *args) {
}
bool cfg_query_setting (uint32_t *args) {
rtc_settings_t settings = (*rtc_get_settings());
rtc_settings_t *settings = rtc_get_settings();
switch (args[0]) {
case SETTING_ID_LED_ENABLE:
args[1] = settings.led_enabled;
args[1] = settings->led_enabled;
break;
default:
return true;
@ -387,17 +387,17 @@ bool cfg_query_setting (uint32_t *args) {
}
bool cfg_update_setting (uint32_t *args) {
rtc_settings_t settings = (*rtc_get_settings());
rtc_settings_t *settings = rtc_get_settings();
switch (args[0]) {
case SETTING_ID_LED_ENABLE:
settings.led_enabled = args[1];
settings->led_enabled = args[1];
break;
default:
return true;
}
rtc_set_settings(&settings);
rtc_save_settings();
return false;
}
@ -450,12 +450,14 @@ void cfg_reset_state (void) {
p.boot_mode = BOOT_MODE_MENU;
}
void cfg_init (void) {
fpga_reg_set(REG_CFG_SCR, CFG_SCR_BOOTLOADER_ENABLED);
cfg_reset_state();
p.usb_output_ready = true;
}
void cfg_process (void) {
uint32_t reg;
uint32_t args[2];

View File

@ -27,7 +27,9 @@ save_type_t cfg_get_save_type (void);
void cfg_get_time (uint32_t *args);
void cfg_set_time (uint32_t *args);
void cfg_reset_state (void);
void cfg_init (void);
void cfg_process (void);

View File

@ -12,12 +12,7 @@ typedef enum {
} cic_region_t;
static bool cic_initialized = false;
static void cic_irq_reset_falling (void) {
led_clear_error(LED_ERROR_CIC);
}
static bool cic_error_active = false;
void cic_reset_parameters (void) {
@ -26,72 +21,70 @@ void cic_reset_parameters (void) {
const uint8_t default_seed = 0x3F;
const uint64_t default_checksum = 0xA536C0F1D859ULL;
uint32_t cic_config_0 = (default_seed << CIC_SEED_BIT) | ((default_checksum >> 32) & 0xFFFF);
uint32_t cic_config_1 = (default_checksum & 0xFFFFFFFFUL);
uint32_t cfg[2] = {
(default_seed << CIC_SEED_BIT) | ((default_checksum >> 32) & 0xFFFF),
(default_checksum & 0xFFFFFFFFUL)
};
if (region == REGION_PAL) {
cic_config_0 |= CIC_REGION;
cfg[0] |= CIC_REGION;
}
fpga_reg_set(REG_CIC_0, cic_config_0);
fpga_reg_set(REG_CIC_1, cic_config_1);
fpga_reg_set(REG_CIC_0, cfg[0]);
fpga_reg_set(REG_CIC_1, cfg[1]);
}
void cic_set_parameters (uint32_t *args) {
uint32_t cic_config_0 = args[0] & (0x00FFFFFF);
uint32_t cic_config_1 = args[1];
uint32_t cfg[2] = {
args[0] & (0x00FFFFFF),
args[1]
};
cic_config_0 |= fpga_reg_get(REG_CIC_0) & (CIC_64DD_MODE | CIC_REGION);
cfg[0] |= fpga_reg_get(REG_CIC_0) & (CIC_64DD_MODE | CIC_REGION);
if (args[0] & (1 << 24)) {
cic_config_0 |= CIC_DISABLED;
cfg[0] |= CIC_DISABLED;
}
fpga_reg_set(REG_CIC_0, cic_config_0);
fpga_reg_set(REG_CIC_1, cic_config_1);
fpga_reg_set(REG_CIC_0, cfg[0]);
fpga_reg_set(REG_CIC_1, cfg[1]);
}
void cic_set_dd_mode (bool enabled) {
uint32_t cic_config_0 = fpga_reg_get(REG_CIC_0);
uint32_t cfg = fpga_reg_get(REG_CIC_0);
if (enabled) {
cic_config_0 |= CIC_64DD_MODE;
cfg |= CIC_64DD_MODE;
} else {
cic_config_0 &= ~(CIC_64DD_MODE);
cfg &= ~(CIC_64DD_MODE);
}
fpga_reg_set(REG_CIC_0, cic_config_0);
fpga_reg_set(REG_CIC_0, cfg);
}
void cic_init (void) {
hw_gpio_irq_setup(GPIO_ID_N64_RESET, GPIO_IRQ_FALLING, cic_irq_reset_falling);
cic_reset_parameters();
}
void cic_process (void) {
if (!cic_initialized) {
if (rtc_is_initialized()) {
cic_reset_parameters();
cic_initialized = true;
} else {
return;
}
}
uint32_t cfg = fpga_reg_get(REG_CIC_0);
uint32_t cic_config_0 = fpga_reg_get(REG_CIC_0);
if (cfg & CIC_INVALID_REGION_DETECTED) {
cfg ^= CIC_REGION;
cfg |= CIC_INVALID_REGION_RESET;
fpga_reg_set(REG_CIC_0, cfg);
if (cic_config_0 & CIC_INVALID_REGION_DETECTED) {
cic_config_0 ^= CIC_REGION;
cic_config_0 |= CIC_INVALID_REGION_RESET;
fpga_reg_set(REG_CIC_0, cic_config_0);
if (cic_config_0 & CIC_REGION) {
rtc_set_region(REGION_PAL);
} else {
rtc_set_region(REGION_NTSC);
}
cic_region_t region = (cfg & CIC_REGION) ? REGION_PAL : REGION_NTSC;
rtc_set_region(region);
cic_error_active = true;
led_blink_error(LED_ERROR_CIC);
}
if (cic_error_active && (!hw_gpio_get(GPIO_ID_N64_RESET))) {
cic_error_active = false;
led_clear_error(LED_ERROR_CIC);
}
}

View File

@ -9,7 +9,9 @@
void cic_reset_parameters (void);
void cic_set_parameters (uint32_t *args);
void cic_set_dd_mode (bool enabled);
void cic_init (void);
void cic_process (void);

View File

@ -1,10 +1,9 @@
#include <stdint.h>
#include "dd.h"
#include "fpga.h"
#include "hw.h"
#include "led.h"
#include "rtc.h"
#include "sd.h"
#include "timer.h"
#include "usb.h"
@ -20,7 +19,7 @@
#define DD_DRIVE_ID_DEVELOPMENT (0x0004)
#define DD_VERSION_RETAIL (0x0114)
#define DD_SPIN_UP_TIME (2000)
#define DD_SPIN_UP_TIME_MS (2000)
#define DD_THB_UNMAPPED (0xFFFFFFFF)
#define DD_THB_WRITABLE_FLAG (1 << 31)
@ -75,7 +74,6 @@ struct process {
rtc_time_t time;
bool disk_spinning;
bool cmd_response_delayed;
bool cmd_response_ready;
bool bm_running;
bool transfer_mode;
bool full_track_transfer;
@ -178,10 +176,6 @@ static bool dd_block_write_request (void) {
return true;
}
static void dd_set_cmd_response_ready (void) {
p.cmd_response_ready = true;
}
void dd_set_block_ready (bool valid) {
p.block_ready = true;
@ -284,13 +278,13 @@ void dd_handle_button (void) {
}
}
void dd_init (void) {
fpga_reg_set(REG_DD_SCR, 0);
fpga_reg_set(REG_DD_HEAD_TRACK, 0);
fpga_reg_set(REG_DD_DRIVE_ID, DD_DRIVE_ID_RETAIL);
p.state = STATE_IDLE;
p.cmd_response_delayed = false;
p.cmd_response_ready = false;
p.disk_spinning = false;
p.bm_running = false;
p.drive_type = DD_DRIVE_TYPE_RETAIL;
@ -299,6 +293,7 @@ void dd_init (void) {
dd_set_disk_mapping(0, 0);
}
void dd_process (void) {
uint32_t starting_scr = fpga_reg_get(REG_DD_SCR);
uint32_t scr = starting_scr;
@ -306,7 +301,6 @@ void dd_process (void) {
if (scr & DD_SCR_HARD_RESET) {
p.state = STATE_IDLE;
p.cmd_response_delayed = false;
p.cmd_response_ready = false;
p.disk_spinning = false;
p.bm_running = false;
p.head_track = 0;
@ -319,19 +313,16 @@ void dd_process (void) {
uint16_t data = cmd_data & 0xFFFF;
if (p.cmd_response_delayed) {
if (p.cmd_response_ready) {
if (timer_countdown_elapsed(TIMER_ID_DD)) {
p.cmd_response_delayed = false;
fpga_reg_set(REG_DD_HEAD_TRACK, DD_HEAD_TRACK_INDEX_LOCK | data);
scr |= DD_SCR_CMD_READY;
}
} else if ((cmd == DD_CMD_SEEK_READ) || (cmd == DD_CMD_SEEK_WRITE)) {
p.cmd_response_delayed = true;
p.cmd_response_ready = false;
if (!p.disk_spinning) {
p.disk_spinning = true;
hw_tim_setup(TIM_ID_DD, DD_SPIN_UP_TIME, dd_set_cmd_response_ready);
} else {
p.cmd_response_ready = true;
timer_countdown_start(TIMER_ID_DD, DD_SPIN_UP_TIME_MS);
}
fpga_reg_set(REG_DD_HEAD_TRACK, p.head_track & ~(DD_HEAD_TRACK_INDEX_LOCK));
p.head_track = data & DD_HEAD_TRACK_MASK;

View File

@ -27,7 +27,9 @@ bool dd_get_sd_mode (void);
void dd_set_sd_mode (bool value);
void dd_set_disk_mapping (uint32_t address, uint32_t length);
void dd_handle_button (void);
void dd_init (void);
void dd_process (void);

View File

@ -40,10 +40,11 @@ void flashram_init (void) {
}
}
void flashram_process (void) {
uint32_t scr = fpga_reg_get(REG_FLASHRAM_SCR);
enum operation op = flashram_operation_type(scr);
uint8_t read_buffer[FLASHRAM_PAGE_SIZE];
uint8_t page_buffer[FLASHRAM_PAGE_SIZE];
uint8_t write_buffer[FLASHRAM_PAGE_SIZE];
uint32_t address = FLASHRAM_ADDRESS;
uint32_t erase_size = (op == OP_ERASE_SECTOR) ? FLASHRAM_SECTOR_SIZE : FLASHRAM_SIZE;
@ -63,10 +64,10 @@ void flashram_process (void) {
break;
case OP_WRITE_PAGE:
fpga_mem_read(FLASHRAM_BUFFER_ADDRESS, FLASHRAM_PAGE_SIZE, read_buffer);
fpga_mem_read(FLASHRAM_BUFFER_ADDRESS, FLASHRAM_PAGE_SIZE, page_buffer);
fpga_mem_read(address, FLASHRAM_PAGE_SIZE, write_buffer);
for (int i = 0; i < FLASHRAM_PAGE_SIZE; i++) {
write_buffer[i] &= read_buffer[i];
write_buffer[i] &= page_buffer[i];
}
fpga_mem_write(address, FLASHRAM_PAGE_SIZE, write_buffer);
fpga_reg_set(REG_FLASHRAM_SCR, FLASHRAM_SCR_DONE);

View File

@ -3,6 +3,7 @@
void flashram_init (void);
void flashram_process (void);

View File

@ -7,8 +7,8 @@ uint8_t fpga_id_get (void) {
uint8_t id;
hw_spi_start();
hw_spi_trx((uint8_t *) (&cmd), 1, SPI_TX);
hw_spi_trx(&id, 1, SPI_RX);
hw_spi_tx((uint8_t *) (&cmd), 1);
hw_spi_rx(&id, 1);
hw_spi_stop();
return id;
@ -19,9 +19,9 @@ uint32_t fpga_reg_get (fpga_reg_t reg) {
uint32_t value;
hw_spi_start();
hw_spi_trx((uint8_t *) (&cmd), 1, SPI_TX);
hw_spi_trx(&reg, 1, SPI_TX);
hw_spi_trx((uint8_t *) (&value), 4, SPI_RX);
hw_spi_tx((uint8_t *) (&cmd), 1);
hw_spi_tx(&reg, 1);
hw_spi_rx((uint8_t *) (&value), 4);
hw_spi_stop();
return value;
@ -31,9 +31,9 @@ void fpga_reg_set (fpga_reg_t reg, uint32_t value) {
fpga_cmd_t cmd = CMD_REG_WRITE;
hw_spi_start();
hw_spi_trx((uint8_t *) (&cmd), 1, SPI_TX);
hw_spi_trx(&reg, 1, SPI_TX);
hw_spi_trx((uint8_t *) (&value), 4, SPI_TX);
hw_spi_tx((uint8_t *) (&cmd), 1);
hw_spi_tx(&reg, 1);
hw_spi_tx((uint8_t *) (&value), 4);
hw_spi_stop();
}
@ -50,9 +50,9 @@ void fpga_mem_read (uint32_t address, size_t length, uint8_t *buffer) {
while (fpga_reg_get(REG_MEM_SCR) & MEM_SCR_BUSY);
hw_spi_start();
hw_spi_trx((uint8_t *) (&cmd), 1, SPI_TX);
hw_spi_trx(&buffer_address, 1, SPI_TX);
hw_spi_trx(buffer, length, SPI_RX);
hw_spi_tx((uint8_t *) (&cmd), 1);
hw_spi_tx(&buffer_address, 1);
hw_spi_rx(buffer, length);
hw_spi_stop();
}
@ -65,9 +65,9 @@ void fpga_mem_write (uint32_t address, size_t length, uint8_t *buffer) {
}
hw_spi_start();
hw_spi_trx((uint8_t *) (&cmd), 1, SPI_TX);
hw_spi_trx(&buffer_address, 1, SPI_TX);
hw_spi_trx(buffer, length, SPI_TX);
hw_spi_tx((uint8_t *) (&cmd), 1);
hw_spi_tx(&buffer_address, 1);
hw_spi_tx(buffer, length);
hw_spi_stop();
fpga_reg_set(REG_MEM_ADDRESS, address);
@ -95,8 +95,8 @@ uint8_t fpga_usb_status_get (void) {
uint8_t status;
hw_spi_start();
hw_spi_trx((uint8_t *) (&cmd), 1, SPI_TX);
hw_spi_trx(&status, 1, SPI_RX);
hw_spi_tx((uint8_t *) (&cmd), 1);
hw_spi_rx(&status, 1);
hw_spi_stop();
return status;
@ -107,8 +107,8 @@ uint8_t fpga_usb_pop (void) {
uint8_t data;
hw_spi_start();
hw_spi_trx((uint8_t *) (&cmd), 1, SPI_TX);
hw_spi_trx(&data, 1, SPI_RX);
hw_spi_tx((uint8_t *) (&cmd), 1);
hw_spi_rx(&data, 1);
hw_spi_stop();
return data;
@ -118,7 +118,7 @@ void fpga_usb_push (uint8_t data) {
fpga_cmd_t cmd = CMD_USB_WRITE;
hw_spi_start();
hw_spi_trx((uint8_t *) (&cmd), 1, SPI_TX);
hw_spi_trx(&data, 1, SPI_TX);
hw_spi_tx((uint8_t *) (&cmd), 1);
hw_spi_tx(&data, 1);
hw_spi_stop();
}

View File

@ -1,39 +0,0 @@
#include "button.h"
#include "cfg.h"
#include "cic.h"
#include "dd.h"
#include "flashram.h"
#include "fpga.h"
#include "isv.h"
#include "rtc.h"
#include "sd.h"
#include "usb.h"
#include "writeback.h"
void gvr_task (void) {
while (fpga_id_get() != FPGA_ID);
button_init();
cfg_init();
cic_init();
dd_init();
flashram_init();
isv_init();
sd_init();
usb_init();
writeback_init();
while (1) {
button_process();
cfg_process();
cic_process();
dd_process();
flashram_process();
isv_process();
rtc_process();
sd_process();
usb_process();
writeback_process();
}
}

View File

@ -1,8 +0,0 @@
#ifndef GVR_H__
#define GVR_H__
void gvr_task (void);
#endif

View File

@ -3,7 +3,70 @@
#include "hw.h"
#define UART_BAUD (115200)
#define CPU_FREQ (64000000UL)
#define UART_BAUD (115200UL)
void hw_set_vector_table (uint32_t offset) {
SCB->VTOR = (__IOM uint32_t) (offset);
}
void hw_enter_critical (void) {
__disable_irq();
}
void hw_exit_critical (void) {
__enable_irq();
}
static void hw_clock_init (void) {
FLASH->ACR |= (FLASH_ACR_PRFTEN | (2 << FLASH_ACR_LATENCY_Pos));
while ((FLASH->ACR & FLASH_ACR_LATENCY_Msk) != (2 << FLASH_ACR_LATENCY_Pos));
RCC->PLLCFGR = (
((2 - 1) << RCC_PLLCFGR_PLLR_Pos)
| RCC_PLLCFGR_PLLREN
| (16 << RCC_PLLCFGR_PLLN_Pos)
| ((2 - 1) << RCC_PLLCFGR_PLLM_Pos)
| RCC_PLLCFGR_PLLSRC_HSI
);
RCC->CR |= RCC_CR_PLLON;
while ((RCC->CR & RCC_CR_PLLRDY_Msk) != RCC_CR_PLLRDY);
RCC->CFGR = RCC_CFGR_SW_1;
while ((RCC->CFGR & RCC_CFGR_SWS_Msk) != RCC_CFGR_SWS_1);
}
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);
}
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 (*systick_callback) (void) = NULL;
void hw_systick_config (uint32_t period_ms, void (*callback) (void)) {
SysTick_Config((CPU_FREQ / 1000) * period_ms);
systick_callback = callback;
}
void SysTick_Handler (void) {
if (systick_callback) {
systick_callback();
}
}
typedef enum {
@ -42,22 +105,7 @@ typedef enum {
GPIO_AF_7 = 0x07
} gpio_af_t;
typedef struct {
void (*volatile falling)(void);
void (*volatile rising)(void);
} gpio_irq_callback_t;
static const GPIO_TypeDef *gpios[] = { GPIOA, GPIOB, 0, 0, 0, 0, 0, 0 };
static gpio_irq_callback_t gpio_irq_callbacks[16];
static volatile uint8_t *i2c_data_txptr;
static volatile uint8_t *i2c_data_rxptr;
static volatile uint32_t i2c_next_cr2;
static void (*volatile i2c_callback)(void);
static const TIM_TypeDef *tims[] = { TIM14, TIM16, TIM17, TIM3, TIM1 };
static void (*volatile tim_callbacks[5])(void);
static void hw_gpio_init (gpio_id_t id, gpio_mode_t mode, gpio_ot_t ot, gpio_ospeed_t ospeed, gpio_pupd_t pupd, gpio_af_t af, int value) {
GPIO_TypeDef tmp;
@ -65,6 +113,8 @@ 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;
tmp.MODER = (gpio->MODER & ~(GPIO_MODER_MODE0_Msk << (pin * 2)));
tmp.OTYPER = (gpio->OTYPER & ~(GPIO_OTYPER_OT0_Msk << pin));
tmp.OSPEEDR = (gpio->OSPEEDR & ~(GPIO_OSPEEDR_OSPEED0_Msk << (pin * 2)));
@ -80,22 +130,6 @@ static void hw_gpio_init (gpio_id_t id, gpio_mode_t mode, gpio_ot_t ot, gpio_osp
gpio->MODER = (tmp.MODER | (mode << (pin * 2)));
}
void hw_gpio_irq_setup (gpio_id_t id, gpio_irq_t irq, void (*callback)(void)) {
uint8_t port = ((id >> 4) & 0x07);
uint8_t pin = (id & 0x0F);
__disable_irq();
if (irq == GPIO_IRQ_FALLING) {
EXTI->FTSR1 |= (EXTI_FTSR1_FT0 << pin);
gpio_irq_callbacks[pin].falling = callback;
} else {
EXTI->RTSR1 |= (EXTI_RTSR1_RT0 << pin);
gpio_irq_callbacks[pin].rising = callback;
}
EXTI->EXTICR[pin / 4] |= (port << (8 * (pin % 4)));
EXTI->IMR1 |= (EXTI_IMR1_IM0 << pin);
__enable_irq();
}
uint32_t hw_gpio_get (gpio_id_t id) {
GPIO_TypeDef *gpio = ((GPIO_TypeDef *) (gpios[(id >> 4) & 0x07]));
uint8_t pin = (id & 0x0F);
@ -114,6 +148,20 @@ void hw_gpio_reset (gpio_id_t id) {
gpio->BSRR = (GPIO_BSRR_BR0 << pin);
}
static void hw_uart_init (void) {
RCC->APBENR2 |= (RCC_APBENR2_USART1EN | RCC_APBENR2_SYSCFGEN);
SYSCFG->CFGR1 |= (SYSCFG_CFGR1_PA12_RMP | SYSCFG_CFGR1_PA11_RMP);
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;
}
void hw_uart_read (uint8_t *data, int length) {
for (int i = 0; i < length; i++) {
while (!(USART1->ISR & USART_ISR_RXNE_RXFNE));
@ -128,10 +176,42 @@ void hw_uart_write (uint8_t *data, int length) {
}
}
void hw_uart_wait_busy (void) {
void hw_uart_write_wait_busy (void) {
while (!(USART1->ISR & USART_ISR_TC));
}
static void hw_spi_init (void) {
RCC->AHBENR |= RCC_AHBENR_DMA1EN;
RCC->APBENR2 |= RCC_APBENR2_SPI1EN;
DMAMUX1_Channel0->CCR = (16 << DMAMUX_CxCR_DMAREQ_ID_Pos);
DMAMUX1_Channel1->CCR = (17 << DMAMUX_CxCR_DMAREQ_ID_Pos);
DMA1_Channel1->CPAR = (uint32_t) (&SPI1->DR);
DMA1_Channel2->CPAR = (uint32_t) (&SPI1->DR);
SPI1->CR2 = (
SPI_CR2_FRXTH |
(8 - 1) << SPI_CR2_DS_Pos |
SPI_CR2_TXDMAEN |
SPI_CR2_RXDMAEN
);
SPI1->CR1 = (
SPI_CR1_SSM |
SPI_CR1_SSI |
SPI_CR1_BR_1 |
SPI_CR1_SPE |
SPI_CR1_MSTR |
SPI_CR1_CPHA
);
hw_gpio_init(GPIO_ID_SPI_CS, GPIO_OUTPUT, GPIO_PP, GPIO_SPEED_HIGH, GPIO_PULL_NONE, GPIO_AF_0, 1);
hw_gpio_init(GPIO_ID_SPI_CLK, GPIO_ALT, GPIO_PP, GPIO_SPEED_HIGH, GPIO_PULL_NONE, GPIO_AF_0, 0);
hw_gpio_init(GPIO_ID_SPI_MOSI, GPIO_ALT, GPIO_PP, GPIO_SPEED_HIGH, GPIO_PULL_NONE, GPIO_AF_0, 0);
hw_gpio_init(GPIO_ID_SPI_MISO, GPIO_ALT, GPIO_PP, GPIO_SPEED_HIGH, GPIO_PULL_DOWN, GPIO_AF_0, 0);
}
void hw_spi_start (void) {
hw_gpio_reset(GPIO_ID_SPI_CS);
}
@ -141,25 +221,17 @@ void hw_spi_stop (void) {
hw_gpio_set(GPIO_ID_SPI_CS);
}
void hw_spi_trx (uint8_t *data, int length, spi_direction_t direction) {
volatile uint8_t dummy __attribute__((unused));
void hw_spi_rx (uint8_t *data, int length) {
volatile uint8_t dummy = 0x00;
DMA1_Channel1->CNDTR = length;
DMA1_Channel2->CNDTR = length;
if (direction == SPI_TX) {
DMA1_Channel1->CMAR = (uint32_t) (&dummy);
DMA1_Channel1->CCR = DMA_CCR_EN;
DMA1_Channel1->CMAR = (uint32_t) (data);
DMA1_Channel1->CCR = (DMA_CCR_MINC | DMA_CCR_EN);
DMA1_Channel2->CMAR = (uint32_t) (data);
DMA1_Channel2->CCR = (DMA_CCR_MINC | DMA_CCR_DIR | DMA_CCR_EN);
} else {
DMA1_Channel1->CMAR = (uint32_t) (data);
DMA1_Channel1->CCR = (DMA_CCR_MINC | DMA_CCR_EN);
DMA1_Channel2->CMAR = (uint32_t) (&dummy);
DMA1_Channel2->CCR = (DMA_CCR_DIR | DMA_CCR_EN);
}
DMA1_Channel2->CMAR = (uint32_t) (&dummy);
DMA1_Channel2->CCR = (DMA_CCR_DIR | DMA_CCR_EN);
while (DMA1_Channel1->CNDTR || DMA1_Channel2->CNDTR);
@ -167,57 +239,69 @@ void hw_spi_trx (uint8_t *data, int length, spi_direction_t direction) {
DMA1_Channel2->CCR = 0;
}
void hw_i2c_read (uint8_t i2c_address, uint8_t address, uint8_t *data, uint8_t length, void (*callback)(void)) {
i2c_data_rxptr = data;
i2c_callback = callback;
I2C1->TXDR = address;
i2c_next_cr2 = (
I2C_CR2_AUTOEND |
(length << I2C_CR2_NBYTES_Pos) |
I2C_CR2_START |
I2C_CR2_RD_WRN |
(i2c_address << I2C_CR2_SADD_Pos)
);
I2C1->CR2 = (
(1 << I2C_CR2_NBYTES_Pos) |
I2C_CR2_START |
(i2c_address << I2C_CR2_SADD_Pos)
);
void hw_spi_tx (uint8_t *data, int length) {
volatile uint8_t dummy __attribute__((unused));
DMA1_Channel1->CNDTR = length;
DMA1_Channel2->CNDTR = length;
DMA1_Channel1->CMAR = (uint32_t) (&dummy);
DMA1_Channel1->CCR = DMA_CCR_EN;
DMA1_Channel2->CMAR = (uint32_t) (data);
DMA1_Channel2->CCR = (DMA_CCR_MINC | DMA_CCR_DIR | DMA_CCR_EN);
while (DMA1_Channel1->CNDTR || DMA1_Channel2->CNDTR);
DMA1_Channel1->CCR = 0;
DMA1_Channel2->CCR = 0;
}
void hw_i2c_write (uint8_t i2c_address, uint8_t address, uint8_t *data, uint8_t length, void (*callback)(void)) {
i2c_data_txptr = data;
i2c_callback = callback;
I2C1->TXDR = address;
I2C1->CR2 = (
I2C_CR2_AUTOEND |
((length + 1) << I2C_CR2_NBYTES_Pos) |
I2C_CR2_START |
(i2c_address << I2C_CR2_SADD_Pos)
);
static void hw_i2c_init (void) {
RCC->APBENR1 |= RCC_APBENR1_I2C1EN;
I2C1->CR1 &= ~(I2C_CR1_PE);
I2C1->TIMINGR = 0x10901032UL;
I2C1->CR1 |= I2C_CR1_PE;
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);
}
uint32_t hw_i2c_get_error (void) {
return (I2C1->ISR & I2C_ISR_NACKF);
}
void hw_i2c_raw (uint8_t i2c_address, uint8_t *tx_data, uint8_t tx_length, uint8_t *rx_data, uint8_t rx_length) {
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);
if (tx_length > 0) {
I2C1->ICR = I2C_ICR_NACKCF;
I2C1->CR2 = (
((rx_length == 0) ? I2C_CR2_AUTOEND : 0) |
((rx_length > 0) ? 0 : I2C_CR2_AUTOEND) |
(tx_length << I2C_CR2_NBYTES_Pos) |
I2C_CR2_START |
(i2c_address << I2C_CR2_SADD_Pos)
(address << I2C_CR2_SADD_Pos)
);
for (int i = 0; i < tx_length; i++) {
while (!(I2C1->ISR & I2C_ISR_TXIS));
I2C1->TXDR = *tx_data++;
I2C1->CR2 |= I2C_CR2_START;
uint8_t left = tx_length;
while (left > 0) {
uint32_t isr = I2C1->ISR;
if (isr & I2C_ISR_TXIS) {
I2C1->TXDR = *tx_data++;
left -= 1;
}
if (isr & I2C_ISR_NACKF) {
return I2C_ERR_NACK;
}
}
if (!(I2C1->CR2 & I2C_CR2_AUTOEND)) {
while (!(I2C1->ISR & (I2C_ISR_NACKF | I2C_ISR_TC)));
if (rx_length == 0) {
return I2C_OK;
}
if (left == 0) {
while (!(I2C1->ISR & I2C_ISR_TC));
}
}
@ -225,102 +309,31 @@ void hw_i2c_raw (uint8_t i2c_address, uint8_t *tx_data, uint8_t tx_length, uint8
I2C1->CR2 = (
I2C_CR2_AUTOEND |
(rx_length << I2C_CR2_NBYTES_Pos) |
I2C_CR2_START |
I2C_CR2_RD_WRN |
(i2c_address << I2C_CR2_SADD_Pos)
(address << I2C_CR2_SADD_Pos)
);
for (int i = 0; i < rx_length; i++) {
while (!(I2C1->ISR & I2C_ISR_RXNE));
*rx_data++ = I2C1->RXDR;
I2C1->CR2 |= I2C_CR2_START;
uint8_t left = rx_length;
while (left > 0) {
uint32_t isr = I2C1->ISR;
if (isr & I2C_ISR_RXNE) {
*rx_data++ = I2C1->RXDR;
left -= 1;
}
}
}
if ((tx_length > 0) || (rx_length > 0)) {
while (!(I2C1->ISR & I2C_ISR_STOPF));
}
return I2C_OK;
}
void hw_i2c_disable_irq (void) {
NVIC_DisableIRQ(I2C1_IRQn);
}
void hw_i2c_enable_irq (void) {
NVIC_EnableIRQ(I2C1_IRQn);
}
static void hw_crc32_init (void) {
RCC->AHBENR |= RCC_AHBENR_CRCEN;
void hw_tim_setup (tim_id_t id, uint16_t delay, void (*callback)(void)) {
if (delay == 0) {
if (callback) {
callback();
}
return;
}
TIM_TypeDef *tim = ((TIM_TypeDef *) (tims[id]));
tim->CR1 = (TIM_CR1_OPM | TIM_CR1_URS);
tim->PSC = (64000 - 1);
tim->ARR = delay;
tim->DIER = TIM_DIER_UIE;
tim->EGR = TIM_EGR_UG;
tim->SR = 0;
tim->CR1 |= TIM_CR1_CEN;
tim_callbacks[id] = callback;
}
void hw_tim_stop (tim_id_t id) {
TIM_TypeDef *tim = ((TIM_TypeDef *) (tims[id]));
tim->CR1 &= ~(TIM_CR1_CEN);
tim_callbacks[id] = 0;
}
void hw_tim_disable_irq (tim_id_t id) {
switch (id) {
case TIM_ID_CIC:
NVIC_DisableIRQ(TIM14_IRQn);
break;
case TIM_ID_RTC:
NVIC_DisableIRQ(TIM16_IRQn);
break;
case TIM_ID_SD:
NVIC_DisableIRQ(TIM17_IRQn);
break;
case TIM_ID_DD:
NVIC_DisableIRQ(TIM3_IRQn);
break;
case TIM_ID_LED:
NVIC_DisableIRQ(TIM1_BRK_UP_TRG_COM_IRQn);
break;
default:
break;
}
}
void hw_tim_enable_irq (tim_id_t id) {
switch (id) {
case TIM_ID_CIC:
NVIC_EnableIRQ(TIM14_IRQn);
break;
case TIM_ID_RTC:
NVIC_EnableIRQ(TIM16_IRQn);
break;
case TIM_ID_SD:
NVIC_EnableIRQ(TIM17_IRQn);
break;
case TIM_ID_DD:
NVIC_EnableIRQ(TIM3_IRQn);
break;
case TIM_ID_LED:
NVIC_EnableIRQ(TIM1_BRK_UP_TRG_COM_IRQn);
break;
default:
break;
}
}
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));
}
CRC->CR = (CRC_CR_REV_OUT | CRC_CR_REV_IN_0);
}
void hw_crc32_reset (void) {
@ -334,10 +347,15 @@ uint32_t hw_crc32_calculate (uint8_t *data, uint32_t length) {
return (CRC->DR ^ 0xFFFFFFFF);
}
uint32_t hw_flash_size (void) {
return FLASH_SIZE;
}
hw_flash_t hw_flash_read (uint32_t offset) {
return *(uint64_t *) (FLASH_BASE + offset);
}
static void hw_flash_unlock (void) {
while (FLASH->SR & FLASH_SR_BSY1);
if (FLASH->CR & FLASH_CR_LOCK) {
@ -363,9 +381,6 @@ void hw_flash_program (uint32_t offset, hw_flash_t value) {
FLASH->CR &= ~(FLASH_CR_PG);
}
hw_flash_t hw_flash_read (uint32_t offset) {
return *(uint64_t *) (FLASH_BASE + offset);
}
void hw_reset (loader_parameters_t *parameters) {
if (parameters != NULL) {
@ -382,6 +397,7 @@ void hw_reset (loader_parameters_t *parameters) {
NVIC_SystemReset();
}
void hw_loader_get_parameters (loader_parameters_t *parameters) {
RCC->APBENR1 |= RCC_APBENR1_PWREN | RCC_APBENR1_RTCAPBEN;
parameters->magic = TAMP->BKP0R;
@ -399,280 +415,44 @@ void hw_loader_get_parameters (loader_parameters_t *parameters) {
RCC->APBENR1 &= ~(RCC_APBENR1_PWREN | RCC_APBENR1_RTCAPBEN);
}
static void hw_init_mcu (void) {
FLASH->ACR |= (FLASH_ACR_PRFTEN | (2 << FLASH_ACR_LATENCY_Pos));
while ((FLASH->ACR & FLASH_ACR_LATENCY_Msk) != (2 << FLASH_ACR_LATENCY_Pos));
RCC->PLLCFGR = (
((2 - 1) << RCC_PLLCFGR_PLLR_Pos)
| RCC_PLLCFGR_PLLREN
| (16 << RCC_PLLCFGR_PLLN_Pos)
| ((2 - 1) << RCC_PLLCFGR_PLLM_Pos)
| RCC_PLLCFGR_PLLSRC_HSI
);
RCC->CR |= RCC_CR_PLLON;
while ((RCC->CR & RCC_CR_PLLRDY_Msk) != RCC_CR_PLLRDY);
RCC->CFGR = RCC_CFGR_SW_1;
while ((RCC->CFGR & RCC_CFGR_SWS_Msk) != RCC_CFGR_SWS_1);
RCC->IOPENR |= RCC_IOPENR_GPIOAEN | RCC_IOPENR_GPIOBEN;
SysTick->LOAD = (((64000000 / 1000)) - 1);
SysTick->VAL = 0;
SysTick->CTRL = (SysTick_CTRL_CLKSOURCE_Msk | SysTick_CTRL_ENABLE_Msk);
static void hw_led_init (void) {
hw_gpio_init(GPIO_ID_LED, GPIO_OUTPUT, GPIO_PP, GPIO_SPEED_VLOW, GPIO_PULL_NONE, GPIO_AF_0, 0);
}
static void hw_init_spi (void) {
RCC->AHBENR |= RCC_AHBENR_DMA1EN;
RCC->APBENR2 |= RCC_APBENR2_SPI1EN;
DMAMUX1_Channel0->CCR = (16 << DMAMUX_CxCR_DMAREQ_ID_Pos);
DMAMUX1_Channel1->CCR = (17 << DMAMUX_CxCR_DMAREQ_ID_Pos);
DMA1_Channel1->CPAR = (uint32_t) (&SPI1->DR);
DMA1_Channel2->CPAR = (uint32_t) (&SPI1->DR);
SPI1->CR2 = (
SPI_CR2_FRXTH |
(8 - 1) << SPI_CR2_DS_Pos |
SPI_CR2_TXDMAEN |
SPI_CR2_RXDMAEN
);
SPI1->CR1 = (
SPI_CR1_SSM |
SPI_CR1_SSI |
SPI_CR1_BR_1 |
SPI_CR1_SPE |
SPI_CR1_MSTR |
SPI_CR1_CPHA
);
hw_gpio_init(GPIO_ID_SPI_CS, GPIO_OUTPUT, GPIO_PP, GPIO_SPEED_HIGH, GPIO_PULL_NONE, GPIO_AF_0, 1);
hw_gpio_init(GPIO_ID_SPI_CLK, GPIO_ALT, GPIO_PP, GPIO_SPEED_HIGH, GPIO_PULL_NONE, GPIO_AF_0, 0);
hw_gpio_init(GPIO_ID_SPI_MISO, GPIO_ALT, GPIO_PP, GPIO_SPEED_HIGH, GPIO_PULL_DOWN, GPIO_AF_0, 0);
hw_gpio_init(GPIO_ID_SPI_MOSI, GPIO_ALT, GPIO_PP, GPIO_SPEED_HIGH, GPIO_PULL_NONE, GPIO_AF_0, 0);
}
static void hw_init_i2c (void) {
RCC->APBENR1 |= RCC_APBENR1_I2C1EN;
I2C1->TIMINGR = 0x80821B20UL;
I2C1->CR1 |= (I2C_CR1_TCIE | I2C_CR1_STOPIE | I2C_CR1_RXIE | I2C_CR1_TXIE | I2C_CR1_PE);
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);
}
static void hw_init_uart (void) {
RCC->APBENR2 |= (RCC_APBENR2_USART1EN | RCC_APBENR2_SYSCFGEN);
SYSCFG->CFGR1 |= (SYSCFG_CFGR1_PA12_RMP | SYSCFG_CFGR1_PA11_RMP);
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 = (64000000UL) / 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;
}
static void hw_init_tim (void) {
RCC->APBENR1 |= (
RCC_APBENR1_DBGEN |
RCC_APBENR1_TIM3EN
);
RCC->APBENR2 |= (
RCC_APBENR2_TIM17EN |
RCC_APBENR2_TIM16EN |
RCC_APBENR2_TIM14EN |
RCC_APBENR2_USART1EN |
RCC_APBENR2_TIM1EN
);
DBG->APBFZ1 |= DBG_APB_FZ1_DBG_TIM3_STOP;
DBG->APBFZ2 |= (
DBG_APB_FZ2_DBG_TIM17_STOP |
DBG_APB_FZ2_DBG_TIM16_STOP |
DBG_APB_FZ2_DBG_TIM14_STOP |
DBG_APB_FZ2_DBG_TIM1_STOP
);
}
static void hw_init_crc (void) {
RCC->AHBENR |= RCC_AHBENR_CRCEN;
CRC->CR = (CRC_CR_REV_OUT | CRC_CR_REV_IN_0);
}
static void hw_init_misc (void) {
hw_gpio_init(GPIO_ID_N64_RESET, GPIO_INPUT, GPIO_PP, GPIO_SPEED_VLOW, GPIO_PULL_DOWN, GPIO_AF_0, 0);
hw_gpio_init(GPIO_ID_N64_CIC_CLK, GPIO_INPUT, GPIO_PP, GPIO_SPEED_VLOW, GPIO_PULL_UP, GPIO_AF_0, 0);
static void hw_misc_init (void) {
hw_gpio_init(GPIO_ID_N64_RESET, GPIO_INPUT, GPIO_OD, GPIO_SPEED_VLOW, GPIO_PULL_DOWN, GPIO_AF_0, 0);
hw_gpio_init(GPIO_ID_N64_CIC_CLK, GPIO_INPUT, GPIO_OD, GPIO_SPEED_VLOW, GPIO_PULL_UP, GPIO_AF_0, 0);
hw_gpio_init(GPIO_ID_N64_CIC_DQ, GPIO_INPUT, GPIO_OD, GPIO_SPEED_VLOW, GPIO_PULL_UP, GPIO_AF_0, 1);
hw_gpio_init(GPIO_ID_FPGA_INT, GPIO_INPUT, GPIO_PP, GPIO_SPEED_VLOW, GPIO_PULL_UP, GPIO_AF_0, 0);
hw_gpio_init(GPIO_ID_RTC_MFP, GPIO_INPUT, GPIO_PP, GPIO_SPEED_VLOW, GPIO_PULL_UP, GPIO_AF_0, 0);
hw_gpio_init(GPIO_ID_FPGA_INT, GPIO_INPUT, GPIO_OD, GPIO_SPEED_VLOW, GPIO_PULL_UP, GPIO_AF_0, 0);
hw_gpio_init(GPIO_ID_RTC_MFP, GPIO_INPUT, GPIO_OD, GPIO_SPEED_VLOW, GPIO_PULL_UP, GPIO_AF_0, 0);
}
void hw_set_vector_table (uint32_t offset) {
SCB->VTOR = (__IOM uint32_t) (offset);
}
void hw_init (void) {
hw_init_mcu();
hw_init_spi();
hw_init_i2c();
hw_init_uart();
hw_init_tim();
hw_init_crc();
hw_init_misc();
NVIC_SetPriority(EXTI0_1_IRQn, 0);
NVIC_SetPriority(EXTI2_3_IRQn, 0);
NVIC_SetPriority(EXTI4_15_IRQn, 0);
NVIC_SetPriority(I2C1_IRQn, 0);
NVIC_SetPriority(TIM14_IRQn, 0);
NVIC_SetPriority(TIM16_IRQn, 0);
NVIC_SetPriority(TIM17_IRQn, 0);
NVIC_SetPriority(TIM3_IRQn, 0);
NVIC_SetPriority(TIM1_BRK_UP_TRG_COM_IRQn, 0);
NVIC_EnableIRQ(EXTI0_1_IRQn);
NVIC_EnableIRQ(EXTI2_3_IRQn);
NVIC_EnableIRQ(EXTI4_15_IRQn);
NVIC_EnableIRQ(I2C1_IRQn);
NVIC_EnableIRQ(TIM14_IRQn);
NVIC_EnableIRQ(TIM16_IRQn);
NVIC_EnableIRQ(TIM17_IRQn);
NVIC_EnableIRQ(TIM3_IRQn);
NVIC_EnableIRQ(TIM1_BRK_UP_TRG_COM_IRQn);
void hw_primer_init (void) {
hw_clock_init();
hw_delay_init();
hw_led_init();
hw_uart_init();
hw_spi_init();
hw_i2c_init();
hw_crc32_init();
}
void hw_loader_init (void) {
hw_init_mcu();
hw_init_spi();
hw_clock_init();
hw_delay_init();
hw_led_init();
hw_spi_init();
}
void hw_primer_init (void) {
hw_init_mcu();
hw_init_spi();
hw_init_i2c();
hw_init_uart();
hw_init_crc();
}
void EXTI0_1_IRQHandler (void) {
for (int i = 0; i <= 1; i++) {
if (EXTI->FPR1 & (EXTI_FPR1_FPIF0 << i)) {
EXTI->FPR1 = (EXTI_FPR1_FPIF0 << i);
if (gpio_irq_callbacks[i].falling) {
gpio_irq_callbacks[i].falling();
}
}
if (EXTI->RPR1 & (EXTI_RPR1_RPIF0 << i)) {
EXTI->RPR1 = (EXTI_RPR1_RPIF0 << i);
if (gpio_irq_callbacks[i].rising) {
gpio_irq_callbacks[i].rising();
}
}
}
}
void EXTI2_3_IRQHandler (void) {
for (int i = 2; i <= 3; i++) {
if (EXTI->FPR1 & (EXTI_FPR1_FPIF0 << i)) {
EXTI->FPR1 = (EXTI_FPR1_FPIF0 << i);
if (gpio_irq_callbacks[i].falling) {
gpio_irq_callbacks[i].falling();
}
}
if (EXTI->RPR1 & (EXTI_RPR1_RPIF0 << i)) {
EXTI->RPR1 = (EXTI_RPR1_RPIF0 << i);
if (gpio_irq_callbacks[i].rising) {
gpio_irq_callbacks[i].rising();
}
}
}
}
void EXTI4_15_IRQHandler (void) {
for (int i = 4; i <= 15; i++) {
if (EXTI->FPR1 & (EXTI_FPR1_FPIF0 << i)) {
EXTI->FPR1 = (EXTI_FPR1_FPIF0 << i);
if (gpio_irq_callbacks[i].falling) {
gpio_irq_callbacks[i].falling();
}
}
if (EXTI->RPR1 & (EXTI_RPR1_RPIF0 << i)) {
EXTI->RPR1 = (EXTI_RPR1_RPIF0 << i);
if (gpio_irq_callbacks[i].rising) {
gpio_irq_callbacks[i].rising();
}
}
}
}
void I2C1_IRQHandler (void) {
if (I2C1->ISR & I2C_ISR_TXIS) {
I2C1->TXDR = *i2c_data_txptr++;
}
if (I2C1->ISR & I2C_ISR_RXNE) {
*i2c_data_rxptr++ = I2C1->RXDR;
}
if (I2C1->ISR & I2C_ISR_TC) {
I2C1->CR2 = i2c_next_cr2;
}
if (I2C1->ISR & I2C_ISR_STOPF) {
I2C1->ICR = I2C_ICR_STOPCF;
if (i2c_callback) {
i2c_callback();
i2c_callback = 0;
}
}
}
void TIM14_IRQHandler (void) {
TIM14->SR &= ~(TIM_SR_UIF);
if (tim_callbacks[0]) {
tim_callbacks[0]();
tim_callbacks[0] = 0;
}
}
void TIM16_IRQHandler (void) {
TIM16->SR &= ~(TIM_SR_UIF);
if (tim_callbacks[1]) {
tim_callbacks[1]();
tim_callbacks[1] = 0;
}
}
void TIM17_IRQHandler (void) {
TIM17->SR &= ~(TIM_SR_UIF);
if (tim_callbacks[2]) {
tim_callbacks[2]();
tim_callbacks[2] = 0;
}
}
void TIM3_IRQHandler (void) {
TIM3->SR &= ~(TIM_SR_UIF);
if (tim_callbacks[3]) {
tim_callbacks[3]();
tim_callbacks[3] = 0;
}
}
void TIM1_BRK_UP_TRG_COM_IRQHandler (void) {
TIM1->SR &= ~(TIM_SR_UIF);
if (tim_callbacks[4]) {
tim_callbacks[4]();
tim_callbacks[4] = 0;
}
void hw_app_init (void) {
hw_clock_init();
hw_led_init();
hw_uart_init();
hw_spi_init();
hw_i2c_init();
hw_crc32_init();
hw_misc_init();
}

View File

@ -7,6 +7,7 @@
#define GPIO_PORT_PIN(p, n) ((((p) & 0x07) << 4) | ((n) & 0x0F))
typedef enum {
GPIO_ID_N64_RESET = GPIO_PORT_PIN(0, 0),
GPIO_ID_N64_CIC_CLK = GPIO_PORT_PIN(0, 1),
@ -25,22 +26,9 @@ typedef enum {
} gpio_id_t;
typedef enum {
GPIO_IRQ_FALLING = 0b01,
GPIO_IRQ_RISING = 0b10,
} gpio_irq_t;
typedef enum {
TIM_ID_CIC = 0,
TIM_ID_RTC = 1,
TIM_ID_SD = 2,
TIM_ID_DD = 3,
TIM_ID_LED = 4,
} tim_id_t;
typedef enum {
SPI_TX,
SPI_RX,
} spi_direction_t;
I2C_OK,
I2C_ERR_NACK,
} i2c_err_t;
typedef uint64_t hw_flash_t;
@ -59,39 +47,45 @@ typedef struct {
} loader_parameters_t;
void hw_gpio_irq_setup (gpio_id_t id, gpio_irq_t irq, void (*callback)(void));
void hw_set_vector_table (uint32_t offset);
void hw_enter_critical (void);
void hw_exit_critical (void);
void hw_delay_ms (uint32_t ms);
void hw_systick_config (uint32_t period_ms, void (*callback) (void));
uint32_t hw_gpio_get (gpio_id_t id);
void hw_gpio_set (gpio_id_t id);
void hw_gpio_reset (gpio_id_t id);
void hw_uart_read (uint8_t *data, int length);
void hw_uart_write (uint8_t *data, int length);
void hw_uart_wait_busy (void);
void hw_uart_write_wait_busy (void);
void hw_spi_start (void);
void hw_spi_stop (void);
void hw_spi_trx (uint8_t *data, int length, spi_direction_t direction);
void hw_i2c_read (uint8_t i2c_address, uint8_t address, uint8_t *data, uint8_t length, void (*callback)(void));
void hw_i2c_write (uint8_t i2c_address, uint8_t address, uint8_t *data, uint8_t length, void (*callback)(void));
uint32_t hw_i2c_get_error (void);
void hw_i2c_raw (uint8_t i2c_address, uint8_t *tx_data, uint8_t tx_length, uint8_t *rx_data, uint8_t rx_length);
void hw_i2c_disable_irq (void);
void hw_i2c_enable_irq (void);
void hw_tim_setup (tim_id_t id, uint16_t delay, void (*callback)(void));
void hw_tim_stop (tim_id_t id);
void hw_tim_disable_irq (tim_id_t id);
void hw_tim_enable_irq (tim_id_t id);
void hw_delay_ms (uint32_t ms);
void hw_spi_rx (uint8_t *data, int length);
void hw_spi_tx (uint8_t *data, int length);
i2c_err_t hw_i2c_trx (uint8_t i2c_address, uint8_t *tx_data, uint8_t tx_length, uint8_t *rx_data, uint8_t rx_length);
void hw_crc32_reset (void);
uint32_t hw_crc32_calculate (uint8_t *data, uint32_t length);
uint32_t hw_flash_size (void);
hw_flash_t hw_flash_read (uint32_t offset);
void hw_flash_erase (void);
void hw_flash_program (uint32_t offset, hw_flash_t value);
hw_flash_t hw_flash_read (uint32_t offset);
void hw_reset (loader_parameters_t *parameters);
void hw_loader_get_parameters (loader_parameters_t *parameters);
void hw_set_vector_table (uint32_t offset);
void hw_init (void);
void hw_loader_init (void);
void hw_primer_init (void);
void hw_loader_init (void);
void hw_app_init (void);
#endif

View File

@ -57,11 +57,13 @@ uint32_t isv_get_address (void) {
return p.address;
}
void isv_init (void) {
p.address = 0;
p.ready = true;
}
void isv_process (void) {
if ((p.address != 0) && p.ready) {
if (isv_get_value(ISV_SETUP_TOKEN_ADDRESS) == ISV_TOKEN) {

View File

@ -8,7 +8,9 @@
bool isv_set_address (uint32_t address);
uint32_t isv_get_address (void);
void isv_init (void);
void isv_process (void);

View File

@ -114,7 +114,7 @@ static void lcmxo2_write_data (uint8_t *buffer, uint32_t length) {
static void lcmxo2_reset_bus (void) {
#ifdef LCMXO2_I2C
uint8_t reset_data = 0;
hw_i2c_raw(LCMXO2_I2C_ADDR_RESET, &reset_data, sizeof(reset_data), NULL, 0);
hw_i2c_trx(LCMXO2_I2C_ADDR_RESET, &reset_data, sizeof(reset_data), NULL, 0);
#else
lcmxo2_reg_set(LCMXO2_CFGCR, CFGCR_RSTE);
lcmxo2_reg_set(LCMXO2_CFGCR, 0);
@ -131,7 +131,7 @@ static void lcmxo2_execute_cmd (uint8_t cmd, uint32_t arg, cmd_type_t type, uint
}
packet_length += length;
}
hw_i2c_raw(LCMXO2_I2C_ADDR_CFG, packet, packet_length, buffer, (write ? 0 : length));
hw_i2c_trx(LCMXO2_I2C_ADDR_CFG, packet, packet_length, buffer, (write ? 0 : length));
#else
uint32_t data = (cmd << 24) | (arg & 0x00FFFFFF);
lcmxo2_reg_set(LCMXO2_CFGCR, CFGCR_WBCE);

View File

@ -1,148 +1,147 @@
#include <stdbool.h>
#include "hw.h"
// #include "hw.h"
#include "led.h"
#include "rtc.h"
#include "task.h"
#include "timer.h"
// #include "rtc.h"
// #include "timer.h"
#define LED_MS_PER_TICK (10)
#define LED_ERROR_TICKS_PERIOD (50)
#define LED_ERROR_TICKS_ON (25)
#define LED_ACT_TICKS_PERIOD (15)
#define LED_ACT_TICKS_ON (6)
// #define LED_MS_PER_TICK (10)
// #define LED_ERROR_TICKS_PERIOD (50)
// #define LED_ERROR_TICKS_ON (25)
// #define LED_ACT_TICKS_PERIOD (15)
// #define LED_ACT_TICKS_ON (6)
static bool error_mode = false;
static uint32_t error_timer = 0;
static volatile bool cic_error = false;
static volatile bool rtc_error = false;
// static bool error_mode = false;
// static uint32_t error_timer = 0;
// static volatile bool cic_error = false;
// static volatile bool rtc_error = false;
static uint32_t act_timer = 0;
static uint32_t current_act_counter = 0;
static volatile uint32_t next_act_counter = 0;
// static uint32_t act_timer = 0;
// static uint32_t current_act_counter = 0;
// static volatile uint32_t next_act_counter = 0;
static void led_task_resume (void) {
task_set_ready(TASK_ID_LED);
}
// static void led_task_resume (void) {
// task_set_ready(TASK_ID_LED);
// }
static void led_set_state (bool state, bool force) {
rtc_settings_t *settings = rtc_get_settings();
if (settings->led_enabled || force) {
if (state) {
hw_gpio_set(GPIO_ID_LED);
} else {
hw_gpio_reset(GPIO_ID_LED);
}
} else {
hw_gpio_reset(GPIO_ID_LED);
}
}
// static void led_set_state (bool state, bool force) {
// rtc_settings_t *settings = rtc_get_settings();
// if (settings->led_enabled || force) {
// if (state) {
// hw_gpio_set(GPIO_ID_LED);
// } else {
// hw_gpio_reset(GPIO_ID_LED);
// }
// } else {
// hw_gpio_reset(GPIO_ID_LED);
// }
// }
static void led_update_error_mode (void) {
if (error_mode) {
if (!(cic_error || rtc_error)) {
led_set_state(false, true);
error_mode = false;
act_timer = 0;
}
} else {
if (cic_error || rtc_error) {
led_set_state(false, true);
error_mode = true;
error_timer = 0;
}
}
}
// static void led_update_error_mode (void) {
// if (error_mode) {
// if (!(cic_error || rtc_error)) {
// led_set_state(false, true);
// error_mode = false;
// act_timer = 0;
// }
// } else {
// if (cic_error || rtc_error) {
// led_set_state(false, true);
// error_mode = true;
// error_timer = 0;
// }
// }
// }
static void led_process_errors (void) {
if (error_timer == 0) {
error_timer = LED_ERROR_TICKS_PERIOD;
if (cic_error) {
error_timer *= 1;
} else if (rtc_error) {
error_timer *= 2;
}
error_timer += LED_ERROR_TICKS_PERIOD;
}
// static void led_process_errors (void) {
// if (error_timer == 0) {
// error_timer = LED_ERROR_TICKS_PERIOD;
// if (cic_error) {
// error_timer *= 1;
// } else if (rtc_error) {
// error_timer *= 2;
// }
// error_timer += LED_ERROR_TICKS_PERIOD;
// }
if (error_timer > 0) {
error_timer -= 1;
if (error_timer >= LED_ERROR_TICKS_PERIOD) {
uint32_t error_cycle = (error_timer % LED_ERROR_TICKS_PERIOD);
if (error_cycle == LED_ERROR_TICKS_ON) {
led_set_state(true, true);
}
if (error_cycle == 0) {
led_set_state(false, true);
}
}
}
}
// if (error_timer > 0) {
// error_timer -= 1;
// if (error_timer >= LED_ERROR_TICKS_PERIOD) {
// uint32_t error_cycle = (error_timer % LED_ERROR_TICKS_PERIOD);
// if (error_cycle == LED_ERROR_TICKS_ON) {
// led_set_state(true, true);
// }
// if (error_cycle == 0) {
// led_set_state(false, true);
// }
// }
// }
// }
static void led_process_act (void) {
if (act_timer == 0) {
if (current_act_counter != next_act_counter) {
current_act_counter = next_act_counter;
act_timer = LED_ACT_TICKS_PERIOD;
}
}
// static void led_process_act (void) {
// if (act_timer == 0) {
// if (current_act_counter != next_act_counter) {
// current_act_counter = next_act_counter;
// act_timer = LED_ACT_TICKS_PERIOD;
// }
// }
if (act_timer > 0) {
act_timer -= 1;
if (act_timer == LED_ACT_TICKS_ON) {
led_set_state(true, false);
}
if (act_timer == 0) {
led_set_state(false, false);
}
}
}
// if (act_timer > 0) {
// act_timer -= 1;
// if (act_timer == LED_ACT_TICKS_ON) {
// led_set_state(true, false);
// }
// if (act_timer == 0) {
// led_set_state(false, false);
// }
// }
// }
void led_blink_error (led_error_t error) {
switch (error) {
case LED_ERROR_CIC:
cic_error = true;
break;
case LED_ERROR_RTC:
rtc_error = true;
break;
}
// switch (error) {
// case LED_ERROR_CIC:
// cic_error = true;
// break;
// case LED_ERROR_RTC:
// rtc_error = true;
// break;
// }
}
void led_clear_error (led_error_t error) {
switch (error) {
case LED_ERROR_CIC:
cic_error = false;
break;
case LED_ERROR_RTC:
rtc_error = false;
break;
}
// switch (error) {
// case LED_ERROR_CIC:
// cic_error = false;
// break;
// case LED_ERROR_RTC:
// rtc_error = false;
// break;
// }
}
void led_blink_act (void) {
next_act_counter += 1;
// next_act_counter += 1;
}
void led_task (void) {
timer_init();
// void led_task (void) {
// timer_init();
while (1) {
hw_tim_setup(TIM_ID_LED, LED_MS_PER_TICK, led_task_resume);
// while (1) {
// hw_tim_setup(TIM_ID_LED, LED_MS_PER_TICK, led_task_resume);
led_update_error_mode();
// led_update_error_mode();
if (error_mode) {
led_process_errors();
} else {
led_process_act();
}
// if (error_mode) {
// led_process_errors();
// } else {
// led_process_act();
// }
timer_update();
// timer_update();
task_yield();
}
}
// task_yield();
// }
// }

View File

@ -11,7 +11,7 @@ typedef enum {
void led_blink_error (led_error_t error);
void led_clear_error (led_error_t error);
void led_blink_act (void);
void led_task (void);
// void led_task (void);
#endif

View File

@ -9,6 +9,7 @@ void no_valid_image (void) {
hw_gpio_set(GPIO_ID_LED);
}
void loader (void) {
if (update_check()) {
hw_loader_init();

View File

@ -69,7 +69,10 @@ static void primer_send_response (uint8_t cmd, uint8_t *buffer, uint8_t tx_lengt
void primer (void) {
hw_primer_init();
vendor_initial_configuration(primer_get_command, primer_send_response);
hw_uart_wait_busy();
hw_uart_write_wait_busy();
hw_reset(NULL);
}

View File

@ -1,8 +1,9 @@
#include <string.h>
#include "fpga.h"
#include "hw.h"
#include "led.h"
#include "rtc.h"
#include "task.h"
#include "timer.h"
#define RTC_I2C_ADDRESS (0xDE)
@ -28,6 +29,8 @@
#define RTC_SETTINGS_VERSION (1)
#define RTC_TIME_REFRESH_PERIOD_MS (500)
static rtc_time_t rtc_time = {
.second = 0x00,
@ -38,17 +41,15 @@ static rtc_time_t rtc_time = {
.month = 0x03,
.year = 0x22
};
static bool rtc_time_valid = false;
static volatile bool rtc_time_pending = false;
static bool rtc_time_pending = false;
static uint8_t rtc_region = 0xFF;
static volatile bool rtc_region_pending = false;
static bool rtc_region_pending = false;
static rtc_settings_t rtc_settings = {
.led_enabled = true,
};
static volatile bool rtc_settings_pending = false;
static volatile bool rtc_initialized = false;
static bool rtc_settings_pending = false;
static const uint8_t rtc_regs_bit_mask[7] = {
0b01111111,
@ -61,29 +62,21 @@ static const uint8_t rtc_regs_bit_mask[7] = {
};
static void rtc_task_resume (void) {
task_set_ready(TASK_ID_RTC);
}
static void rtc_on_error (void) {
rtc_time_valid = false;
led_blink_error(LED_ERROR_RTC);
task_yield();
}
static void rtc_read (uint8_t address, uint8_t *data, uint8_t length) {
hw_i2c_read(RTC_I2C_ADDRESS, address, data, length, rtc_task_resume);
task_yield();
if (hw_i2c_get_error()) {
rtc_on_error();
uint8_t tmp = address;
if (hw_i2c_trx(RTC_I2C_ADDRESS, &tmp, 1, data, length) != I2C_OK) {
led_blink_error(LED_ERROR_RTC);
}
}
static void rtc_write (uint8_t address, uint8_t *data, uint8_t length) {
hw_i2c_write(RTC_I2C_ADDRESS, address, data, length, rtc_task_resume);
task_yield();
if (hw_i2c_get_error()) {
rtc_on_error();
uint8_t tmp[16];
tmp[0] = address;
for (int i = 0; i < length; i++) {
tmp[i + 1] = data[i];
}
if (hw_i2c_trx(RTC_I2C_ADDRESS, tmp, length + 1, NULL, 0) != I2C_OK) {
led_blink_error(LED_ERROR_RTC);
}
}
@ -110,17 +103,13 @@ static void rtc_read_time (void) {
rtc_sanitize_time(regs);
if (!rtc_time_pending) {
rtc_time.second = regs[0];
rtc_time.minute = regs[1];
rtc_time.hour = regs[2];
rtc_time.weekday = regs[3];
rtc_time.day = regs[4];
rtc_time.month = regs[5];
rtc_time.year = regs[6];
rtc_time_valid = true;
}
rtc_time.second = regs[0];
rtc_time.minute = regs[1];
rtc_time.hour = regs[2];
rtc_time.weekday = regs[3];
rtc_time.day = regs[4];
rtc_time.month = regs[5];
rtc_time.year = regs[6];
}
static void rtc_write_time (void) {
@ -161,12 +150,55 @@ static void rtc_write_settings (void) {
rtc_write(RTC_ADDRESS_SRAM_SETTINGS, (uint8_t *) (&rtc_settings), sizeof(rtc_settings));
}
static void rtc_init (void) {
void rtc_get_time (rtc_time_t *time) {
time->second = rtc_time.second;
time->minute = rtc_time.minute;
time->hour = rtc_time.hour;
time->weekday = rtc_time.weekday;
time->day = rtc_time.day;
time->month = rtc_time.month;
time->year = rtc_time.year;
}
void rtc_set_time (rtc_time_t *time) {
rtc_time.second = time->second;
rtc_time.minute = time->minute;
rtc_time.hour = time->hour;
rtc_time.weekday = time->weekday;
rtc_time.day = time->day;
rtc_time.month = time->month;
rtc_time.year = time->year;
rtc_time_pending = true;
}
uint8_t rtc_get_region (void) {
return rtc_region;
}
void rtc_set_region (uint8_t region) {
rtc_region = region;
rtc_region_pending = true;
}
rtc_settings_t *rtc_get_settings (void) {
return (&rtc_settings);
}
void rtc_save_settings (void) {
rtc_settings_pending = true;
}
void rtc_init (void) {
bool uninitialized = false;
const char *magic = "SC64";
uint8_t buffer[4];
uint32_t settings_version;
memset(buffer, 0, 4);
rtc_read(RTC_ADDRESS_SRAM_MAGIC, buffer, 4);
for (int i = 0; i < 4; i++) {
@ -192,143 +224,73 @@ static void rtc_init (void) {
rtc_write(RTC_ADDRESS_SRAM_VERSION, (uint8_t *) (&settings_version), 4);
rtc_write_settings();
}
}
bool rtc_is_initialized (void) {
return rtc_initialized;
}
bool rtc_get_time (rtc_time_t *time) {
bool vaild;
hw_i2c_disable_irq();
hw_tim_disable_irq(TIM_ID_RTC);
time->second = rtc_time.second;
time->minute = rtc_time.minute;
time->hour = rtc_time.hour;
time->weekday = rtc_time.weekday;
time->day = rtc_time.day;
time->month = rtc_time.month;
time->year = rtc_time.year;
vaild = rtc_time_valid;
hw_tim_enable_irq(TIM_ID_RTC);
hw_i2c_enable_irq();
return vaild;
}
void rtc_set_time (rtc_time_t *time) {
hw_i2c_disable_irq();
hw_tim_disable_irq(TIM_ID_RTC);
rtc_time.second = time->second;
rtc_time.minute = time->minute;
rtc_time.hour = time->hour;
rtc_time.weekday = time->weekday;
rtc_time.day = time->day;
rtc_time.month = time->month;
rtc_time.year = time->year;
rtc_time_pending = true;
hw_tim_enable_irq(TIM_ID_RTC);
hw_i2c_enable_irq();
}
uint8_t rtc_get_region (void) {
return rtc_region;
}
void rtc_set_region (uint8_t region) {
rtc_region = region;
rtc_region_pending = true;
}
rtc_settings_t *rtc_get_settings (void) {
return (&rtc_settings);
}
void rtc_set_settings (rtc_settings_t *settings) {
hw_tim_disable_irq(TIM_ID_LED);
rtc_settings = *settings;
rtc_settings_pending = true;
hw_tim_enable_irq(TIM_ID_LED);
}
void rtc_task (void) {
rtc_init();
rtc_read_time();
rtc_read_region();
rtc_read_settings();
rtc_initialized = true;
while (1) {
if (rtc_time_pending) {
rtc_time_pending = false;
rtc_write_time();
}
if (rtc_region_pending) {
rtc_region_pending = false;
rtc_write_region();
}
if (rtc_settings_pending) {
rtc_settings_pending = false;
rtc_write_settings();
}
rtc_read_time();
hw_tim_setup(TIM_ID_RTC, 50, rtc_task_resume);
task_yield();
}
timer_countdown_start(TIMER_ID_RTC, RTC_TIME_REFRESH_PERIOD_MS);
}
void rtc_process (void) {
rtc_time_t time;
uint32_t data[2];
uint32_t scr = fpga_reg_get(REG_RTC_SCR);
if ((scr & RTC_SCR_PENDING) && ((scr & RTC_SCR_MAGIC_MASK) == RTC_SCR_MAGIC)) {
uint32_t data[2];
data[0] = fpga_reg_get(REG_RTC_TIME_0);
data[1] = fpga_reg_get(REG_RTC_TIME_1);
time.weekday = ((data[0] >> 24) & 0xFF) + 1;
time.hour = ((data[0] >> 16) & 0xFF);
time.minute = ((data[0] >> 8) & 0xFF);
time.second = ((data[0] >> 0) & 0xFF);
time.year = ((data[1] >> 16) & 0xFF);
time.month = ((data[1] >> 8) & 0xFF);
time.day = ((data[1] >> 0) & 0xFF);
rtc_set_time(&time);
rtc_time.weekday = ((data[0] >> 24) & 0xFF) + 1;
rtc_time.hour = ((data[0] >> 16) & 0xFF);
rtc_time.minute = ((data[0] >> 8) & 0xFF);
rtc_time.second = ((data[0] >> 0) & 0xFF);
rtc_time.year = ((data[1] >> 16) & 0xFF);
rtc_time.month = ((data[1] >> 8) & 0xFF);
rtc_time.day = ((data[1] >> 0) & 0xFF);
rtc_time_pending = true;
fpga_reg_set(REG_RTC_TIME_0, data[0]);
fpga_reg_set(REG_RTC_TIME_1, data[1]);
fpga_reg_set(REG_RTC_SCR, RTC_SCR_DONE);
}
rtc_get_time(&time);
if (rtc_time_pending) {
rtc_time_pending = false;
rtc_write_time();
}
data[0] = (
((time.weekday - 1) << 24) |
(time.hour << 16) |
(time.minute << 8) |
(time.second << 0)
);
data[1] = (
(time.year << 16) |
(time.month << 8) |
(time.day << 0)
);
if (rtc_region_pending) {
rtc_region_pending = false;
rtc_write_region();
}
fpga_reg_set(REG_RTC_TIME_0, data[0]);
fpga_reg_set(REG_RTC_TIME_1, data[1]);
if (rtc_settings_pending) {
rtc_settings_pending = false;
rtc_write_settings();
}
if (timer_countdown_elapsed(TIMER_ID_RTC)) {
timer_countdown_start(TIMER_ID_RTC, RTC_TIME_REFRESH_PERIOD_MS);
rtc_read_time();
uint32_t data[2];
data[0] = (
((rtc_time.weekday - 1) << 24) |
(rtc_time.hour << 16) |
(rtc_time.minute << 8) |
(rtc_time.second << 0)
);
data[1] = (
(rtc_time.year << 16) |
(rtc_time.month << 8) |
(rtc_time.day << 0)
);
fpga_reg_set(REG_RTC_TIME_0, data[0]);
fpga_reg_set(REG_RTC_TIME_1, data[1]);
}
}

View File

@ -7,28 +7,31 @@
typedef struct {
volatile uint8_t second;
volatile uint8_t minute;
volatile uint8_t hour;
volatile uint8_t weekday;
volatile uint8_t day;
volatile uint8_t month;
volatile uint8_t year;
uint8_t second;
uint8_t minute;
uint8_t hour;
uint8_t weekday;
uint8_t day;
uint8_t month;
uint8_t year;
} rtc_time_t;
typedef struct {
volatile bool led_enabled;
bool led_enabled;
} rtc_settings_t;
bool rtc_is_initialized (void);
bool rtc_get_time (rtc_time_t *time);
void rtc_get_time (rtc_time_t *time);
void rtc_set_time (rtc_time_t *time);
uint8_t rtc_get_region (void);
void rtc_set_region (uint8_t region);
rtc_settings_t *rtc_get_settings (void);
void rtc_set_settings (rtc_settings_t *settings);
void rtc_task (void);
void rtc_save_settings (void);
void rtc_init (void);
void rtc_process (void);

View File

@ -1,9 +1,8 @@
#include <stdbool.h>
#include <stdint.h>
#include "fpga.h"
#include "hw.h"
#include "led.h"
#include "sd.h"
#include "timer.h"
#define SD_INIT_BUFFER_ADDRESS (0x05002800UL)
@ -33,6 +32,8 @@
#define SWITCH_FUNCTION_GROUP_1 (SD_INIT_BUFFER_ADDRESS + 12)
#define SWITCH_FUNCTION_GROUP_1_HS (1 << 1)
#define TIMEOUT_INIT_MS (1000)
#define DAT_BLOCK_MAX_COUNT (256)
#define DAT_TIMEOUT_INIT_MS (2000)
#define DAT_TIMEOUT_DATA_MS (5000)
@ -60,6 +61,12 @@ typedef enum {
DAT_WRITE,
} dat_mode_t;
typedef enum {
DAT_OK,
DAT_ERR_IO,
DAT_ERR_TIMEOUT,
} dat_err_t;
struct process {
bool card_initialized;
@ -67,7 +74,6 @@ struct process {
uint32_t rca;
uint8_t csd[16];
uint8_t cid[16];
volatile bool timeout;
bool byte_swap;
};
@ -75,24 +81,6 @@ struct process {
static struct process p;
static void sd_trigger_timeout (void) {
p.timeout = true;
}
static void sd_prepare_timeout (uint16_t value) {
p.timeout = false;
hw_tim_setup(TIM_ID_SD, value, sd_trigger_timeout);
}
static bool sd_did_timeout (void) {
return p.timeout;
}
static void sd_clear_timeout (void) {
hw_tim_stop(TIM_ID_SD);
p.timeout = false;
}
static void sd_set_clock (sd_clock_t mode) {
fpga_reg_set(REG_SD_SCR, SD_SCR_CLOCK_MODE_OFF);
@ -198,22 +186,25 @@ static void sd_dat_abort (void) {
fpga_reg_set(REG_SD_DAT, SD_DAT_STOP | SD_DAT_FIFO_FLUSH);
}
static bool sd_dat_wait (uint16_t timeout) {
sd_prepare_timeout(timeout);
static dat_err_t sd_dat_wait (uint16_t timeout_ms) {
timer_countdown_start(TIMER_ID_SD, timeout_ms);
do {
uint32_t sd_dat = fpga_reg_get(REG_SD_DAT);
uint32_t sd_dma_scr = fpga_reg_get(REG_SD_DMA_SCR);
led_blink_act();
if ((!(sd_dat & SD_DAT_BUSY)) && (!(sd_dma_scr & DMA_SCR_BUSY))) {
sd_clear_timeout();
return (sd_dat & SD_DAT_ERROR);
if (sd_dat & SD_DAT_ERROR) {
sd_dat_abort();
return DAT_ERR_IO;
}
return DAT_OK;
}
} while (!sd_did_timeout());
} while (!timer_countdown_elapsed(TIMER_ID_SD));
sd_dat_abort();
return true;
return DAT_ERR_TIMEOUT;
}
@ -248,9 +239,9 @@ bool sd_card_init (void) {
arg = (ACMD41_ARG_HCS | ACMD41_ARG_OCR);
}
sd_prepare_timeout(1000);
timer_countdown_start(TIMER_ID_SD, TIMEOUT_INIT_MS);
do {
if (sd_did_timeout()) {
if (timer_countdown_elapsed(TIMER_ID_SD)) {
sd_card_deinit();
return true;
}
@ -266,8 +257,7 @@ bool sd_card_init (void) {
p.card_type_block = (rsp & R3_CCS);
break;
}
} while (1);
sd_clear_timeout();
} while (true);
if (sd_cmd(2, 0, RSP_R2, NULL)) {
sd_card_deinit();
@ -308,8 +298,7 @@ bool sd_card_init (void) {
sd_card_deinit();
return true;
}
sd_dat_wait(DAT_TIMEOUT_INIT_MS);
if (sd_did_timeout()) {
if (sd_dat_wait(DAT_TIMEOUT_INIT_MS) == DAT_ERR_TIMEOUT) {
sd_card_deinit();
return true;
}
@ -326,8 +315,7 @@ bool sd_card_init (void) {
sd_card_deinit();
return true;
}
sd_dat_wait(DAT_TIMEOUT_INIT_MS);
if (sd_did_timeout()) {
if (sd_dat_wait(DAT_TIMEOUT_INIT_MS) == DAT_ERR_TIMEOUT) {
sd_card_deinit();
return true;
}
@ -389,6 +377,7 @@ bool sd_set_byte_swap (bool enabled) {
return false;
}
bool sd_write_sectors (uint32_t address, uint32_t sector, uint32_t count) {
if (!p.card_initialized || (count == 0)) {
return true;
@ -405,8 +394,7 @@ bool sd_write_sectors (uint32_t address, uint32_t sector, uint32_t count) {
return true;
}
sd_dat_prepare(address, blocks, DAT_WRITE);
if (sd_dat_wait(DAT_TIMEOUT_DATA_MS)) {
sd_dat_abort();
if (sd_dat_wait(DAT_TIMEOUT_DATA_MS) != DAT_OK) {
sd_cmd(12, 0, RSP_R1b, NULL);
return true;
}
@ -440,10 +428,8 @@ bool sd_read_sectors (uint32_t address, uint32_t sector, uint32_t count) {
sd_dat_abort();
return true;
}
if (sd_dat_wait(DAT_TIMEOUT_DATA_MS)) {
if (sd_did_timeout()) {
sd_cmd(12, 0, RSP_R1b, NULL);
}
if (sd_dat_wait(DAT_TIMEOUT_DATA_MS) != DAT_OK) {
sd_cmd(12, 0, RSP_R1b, NULL);
return true;
}
sd_cmd(12, 0, RSP_R1b, NULL);
@ -455,6 +441,7 @@ bool sd_read_sectors (uint32_t address, uint32_t sector, uint32_t count) {
return false;
}
bool sd_optimize_sectors (uint32_t address, uint32_t *sector_table, uint32_t count, sd_process_sectors_t sd_process_sectors) {
uint32_t starting_sector = 0;
uint32_t sectors_to_process = 0;
@ -483,12 +470,14 @@ bool sd_optimize_sectors (uint32_t address, uint32_t *sector_table, uint32_t cou
return false;
}
void sd_init (void) {
p.card_initialized = false;
p.byte_swap = false;
sd_set_clock(CLOCK_STOP);
}
void sd_process (void) {
if (p.card_initialized && !sd_card_is_inserted()) {
sd_card_deinit();

View File

@ -3,6 +3,7 @@
#include <stdbool.h>
#include <stdint.h>
#define SD_SECTOR_SIZE (512)
@ -18,10 +19,14 @@ bool sd_card_is_inserted (void);
uint32_t sd_card_get_status (void);
bool sd_card_get_info (uint32_t address);
bool sd_set_byte_swap (bool enabled);
bool sd_write_sectors (uint32_t address, uint32_t sector, uint32_t count);
bool sd_read_sectors (uint32_t address, uint32_t sector, uint32_t count);
bool sd_optimize_sectors (uint32_t address, uint32_t *sector_table, uint32_t count, sd_process_sectors_t sd_process_sectors);
void sd_init (void);
void sd_process (void);

View File

@ -1,135 +0,0 @@
#include <stdbool.h>
#include <stdint.h>
#include <stm32g0xx.h>
#include "task.h"
#define TASK_INITIAL_XPSR (0x21000000UL)
#define TASK_CONTEXT_SWITCH() { SCB->ICSR = (1 << SCB_ICSR_PENDSVSET_Pos); }
#define TASK_STACK_FILL_VALUE (0xDEADBEEF)
typedef struct {
volatile uint32_t sp;
volatile bool ready;
} task_t;
static task_t task_table[__TASK_ID_MAX];
static volatile task_id_t task_current = 0;
static void task_exit (void) {
while (1) {
task_yield();
}
}
static uint32_t task_switch_context (uint32_t sp) {
task_table[task_current].sp = sp;
for (task_id_t id = 0; id < __TASK_ID_MAX; id++) {
if (task_table[id].ready) {
task_current = id;
break;
}
}
return task_table[task_current].sp;
}
void task_create (task_id_t id, void (*code)(void), void *stack, size_t stack_size) {
if (id < __TASK_ID_MAX) {
for (size_t i = 0; i < stack_size; i += sizeof(uint32_t)) {
(*(uint32_t *) (stack + i)) = TASK_STACK_FILL_VALUE;
}
uint32_t *sp = ((uint32_t *) ((uint32_t) (stack) + stack_size));
*--sp = TASK_INITIAL_XPSR;
*--sp = (uint32_t) (code);
*--sp = ((uint32_t) (task_exit));
for (int i = 0; i < 13; i++) {
*--sp = 0;
}
task_t *task = &task_table[id];
task->sp = ((uint32_t) (sp));
task->ready = true;
}
}
void task_yield (void) {
__disable_irq();
task_table[task_current].ready = false;
__enable_irq();
TASK_CONTEXT_SWITCH();
}
void task_set_ready (task_id_t id) {
__disable_irq();
task_table[id].ready = true;
__enable_irq();
TASK_CONTEXT_SWITCH();
}
size_t task_get_stack_usage (void *stack, size_t stack_size) {
for (size_t i = 0; i < stack_size; i += sizeof(uint32_t)) {
if ((*(uint32_t *) (stack + i)) != TASK_STACK_FILL_VALUE) {
return (stack_size - i);
}
}
return 0;
}
__attribute__((naked)) void task_scheduler_start (void) {
uint32_t sp = task_table[task_current].sp;
NVIC_SetPriority(PendSV_IRQn, 3);
asm volatile (
"add %[sp], #32 \n"
"msr psp, %[sp] \n"
"movs r0, #2 \n"
"msr CONTROL, r0 \n"
"isb \n"
"pop {r0-r5} \n"
"mov lr, r5 \n"
"pop {r3} \n"
"pop {r2} \n"
"cpsie i \n"
"bx r3 \n"
:: [sp] "r" (sp)
);
while (1);
}
__attribute__((naked)) void PendSV_Handler (void) {
asm volatile (
"mrs r1, psp \n"
"sub r1, r1, #32 \n"
"mov r0, r1 \n"
"stmia r1!, {r4-r7} \n"
"mov r4, r8 \n"
"mov r5, r9 \n"
"mov r6, r10 \n"
"mov r7, r11 \n"
"stmia r1!, {r4-r7} \n"
"push {lr} \n"
"cpsid i \n"
"blx %[task_switch_context] \n"
"cpsie i \n"
"pop {r2} \n"
"add r0, #16 \n"
"ldmia r0!, {r4-r7} \n"
"mov r8, r4 \n"
"mov r9, r5 \n"
"mov r10, r6 \n"
"mov r11, r7 \n"
"msr psp, r0 \n"
"sub r0, #32 \n"
"ldmia r0!, {r4-r7} \n"
"bx r2 \n"
:: [task_switch_context] "r" (task_switch_context)
);
}

View File

@ -1,23 +0,0 @@
#ifndef TASK_H__
#define TASK_H__
#include <stddef.h>
typedef enum {
TASK_ID_RTC,
TASK_ID_LED,
TASK_ID_GVR,
__TASK_ID_MAX
} task_id_t;
void task_create (task_id_t id, void (*code)(void), void *stack, size_t stack_size);
void task_yield (void);
void task_set_ready (task_id_t id);
size_t task_get_stack_usage (void *stack, size_t stack_size);
void task_scheduler_start (void);
#endif

View File

@ -2,29 +2,55 @@
#include "timer.h"
static volatile uint32_t timer[__TIMER_ID_COUNT];
#define TIMER_PERIOD_MS (50)
uint32_t timer_get (timer_id_t id) {
return (uint32_t) (timer[id]);
}
typedef struct {
volatile bool pending;
volatile bool running;
volatile uint32_t value;
} timer_t;
void timer_set (timer_id_t id, uint32_t ticks) {
hw_tim_disable_irq(TIM_ID_LED);
timer[id] = ticks;
hw_tim_enable_irq(TIM_ID_LED);
}
static timer_t timer[__TIMER_ID_COUNT];
void timer_init (void) {
static void timer_update (void) {
for (timer_id_t id = 0; id < __TIMER_ID_COUNT; id++) {
timer[id] = 0;
}
}
void timer_update (void) {
for (timer_id_t id = 0; id < __TIMER_ID_COUNT; id++) {
if (timer[id] > 0) {
timer[id] -= 1;
if (timer[id].value > 0) {
timer[id].value -= 1;
}
if (timer[id].pending) {
timer[id].pending = false;
} else if(timer[id].value == 0) {
timer[id].running = false;
}
}
}
void timer_countdown_start (timer_id_t id, uint32_t value_ms) {
hw_enter_critical();
if (value_ms > 0) {
timer[id].pending = true;
timer[id].running = true;
timer[id].value = ((value_ms + (TIMER_PERIOD_MS - 1)) / TIMER_PERIOD_MS);
}
hw_exit_critical();
}
void timer_countdown_abort (timer_id_t id) {
hw_enter_critical();
timer[id].pending = false;
timer[id].running = false;
timer[id].value = 0;
hw_exit_critical();
}
bool timer_countdown_elapsed (timer_id_t id) {
return (!timer[id].running);
}
void timer_init (void) {
hw_systick_config(TIMER_PERIOD_MS, timer_update);
}

View File

@ -2,20 +2,25 @@
#define TIMER_H__
#include <stdbool.h>
#include <stdint.h>
typedef enum {
TIMER_ID_DD,
TIMER_ID_RTC,
TIMER_ID_SD,
TIMER_ID_USB,
TIMER_ID_WRITEBACK,
__TIMER_ID_COUNT
} timer_id_t;
uint32_t timer_get (timer_id_t id);
void timer_set (timer_id_t id, uint32_t ticks);
void timer_countdown_start (timer_id_t id, uint32_t value_ms);
void timer_countdown_abort (timer_id_t id);
bool timer_countdown_elapsed (timer_id_t id);
void timer_init (void);
void timer_update (void);
#endif

View File

@ -312,7 +312,7 @@ void update_perform (void) {
fpga_mem_read(parameters.mcu_address - 4, sizeof(length), (uint8_t *) (&length));
if (mcu_update(parameters.mcu_address, length)) {
update_status_notify(UPDATE_STATUS_ERROR);
while (1);
while (true);
}
}
@ -321,7 +321,7 @@ void update_perform (void) {
fpga_mem_read(parameters.fpga_address - 4, sizeof(length), (uint8_t *) (&length));
if (vendor_update(parameters.fpga_address, length) != VENDOR_OK) {
update_status_notify(UPDATE_STATUS_ERROR);
while (1);
while (true);
}
}
@ -330,7 +330,7 @@ void update_perform (void) {
fpga_mem_read(parameters.bootloader_address - 4, sizeof(length), (uint8_t *) (&length));
if (bootloader_update(parameters.bootloader_address, length)) {
update_status_notify(UPDATE_STATUS_ERROR);
while (1);
while (true);
}
}

View File

@ -1,4 +1,3 @@
#include "app.h"
#include "cfg.h"
#include "cic.h"
#include "dd.h"
@ -12,15 +11,15 @@
#include "writeback.h"
#define BOOTLOADER_ADDRESS (0x04E00000UL)
#define BOOTLOADER_LENGTH (1920 * 1024)
#define BOOTLOADER_ADDRESS (0x04E00000UL)
#define BOOTLOADER_LENGTH (1920 * 1024)
#define MEMORY_LENGTH (0x05002980UL)
#define MEMORY_LENGTH (0x05002980UL)
#define RX_FLUSH_ADDRESS (0x07F00000UL)
#define RX_FLUSH_LENGTH (1 * 1024 * 1024)
#define RX_FLUSH_ADDRESS (0x07F00000UL)
#define RX_FLUSH_LENGTH (1 * 1024 * 1024)
#define DEBUG_WRITE_TIMEOUT_TICKS (100)
#define DEBUG_WRITE_TIMEOUT_MS (1000)
enum rx_state {
@ -175,7 +174,7 @@ static void usb_rx_process (void) {
p.response_info.dma_length = 0;
p.response_info.done_callback = NULL;
if (p.rx_cmd == 'U') {
timer_set(TIMER_ID_USB, DEBUG_WRITE_TIMEOUT_TICKS);
timer_countdown_start(TIMER_ID_USB, DEBUG_WRITE_TIMEOUT_MS);
}
}
}
@ -311,9 +310,9 @@ static void usb_rx_process (void) {
p.read_length -= length;
p.read_address += length;
p.read_ready = true;
timer_set(TIMER_ID_USB, DEBUG_WRITE_TIMEOUT_TICKS);
timer_countdown_start(TIMER_ID_USB, DEBUG_WRITE_TIMEOUT_MS);
}
} else if (timer_get(TIMER_ID_USB) == 0) {
} else if (timer_countdown_elapsed(TIMER_ID_USB)) {
p.rx_state = RX_STATE_FLUSH;
p.flush_packet = true;
}
@ -386,7 +385,10 @@ static void usb_rx_process (void) {
p.rx_state = RX_STATE_IDLE;
p.response_pending = true;
p.response_info.data_length = 16;
app_get_stack_usage(p.response_info.data);
p.response_info.data[0] = 0;
p.response_info.data[1] = 0;
p.response_info.data[2] = 0;
p.response_info.data[3] = 0;
break;
default:
@ -521,6 +523,7 @@ bool usb_enqueue_packet (usb_tx_info_t *info) {
return true;
}
bool usb_prepare_read (uint32_t *args) {
if (!p.read_ready) {
return false;
@ -543,6 +546,7 @@ void usb_get_read_info (uint32_t *args) {
args[0] |= (scr & USB_SCR_PWRSAV) ? (1 << 29) : 0;
}
void usb_init (void) {
fpga_reg_set(REG_USB_DMA_SCR, DMA_SCR_STOP);
fpga_reg_set(REG_USB_SCR, USB_SCR_FIFO_FLUSH);
@ -563,6 +567,7 @@ void usb_init (void) {
usb_rx_cmd_counter = 0;
}
void usb_process (void) {
uint32_t scr = fpga_reg_get(REG_USB_SCR);
if (scr & (USB_SCR_PWRSAV | USB_SCR_RESET_STATE | USB_SCR_RESET_PENDING)) {

View File

@ -7,13 +7,13 @@
typedef enum packet_cmd {
PACKET_CMD_BUTTON_TRIGGER = 'B',
PACKET_CMD_DATA_FLUSHED = 'G',
PACKET_CMD_DEBUG_OUTPUT = 'U',
PACKET_CMD_DD_REQUEST = 'D',
PACKET_CMD_ISV_OUTPUT = 'I',
PACKET_CMD_SAVE_WRITEBACK = 'S',
PACKET_CMD_UPDATE_STATUS = 'F',
PACKET_CMD_BUTTON_TRIGGER = 'B',
PACKET_CMD_DATA_FLUSHED = 'G',
PACKET_CMD_DEBUG_OUTPUT = 'U',
PACKET_CMD_DD_REQUEST = 'D',
PACKET_CMD_ISV_OUTPUT = 'I',
PACKET_CMD_SAVE_WRITEBACK = 'S',
PACKET_CMD_UPDATE_STATUS = 'F',
} usb_packet_cmd_e;
@ -29,9 +29,12 @@ typedef struct usb_tx_info {
void usb_create_packet (usb_tx_info_t *info, usb_packet_cmd_e cmd);
bool usb_enqueue_packet (usb_tx_info_t *info);
bool usb_prepare_read (uint32_t *args);
void usb_get_read_info (uint32_t *args);
void usb_init (void);
void usb_process (void);

View File

@ -6,16 +6,19 @@
#include "writeback.h"
#define SAVE_MAX_SECTOR_COUNT (256)
#define EEPROM_ADDRESS (0x05002000)
#define SRAM_FLASHRAM_ADDRESS (0x03FE0000)
#define EEPROM_4K_LENGTH (512)
#define EEPROM_16K_LENGTH (2048)
#define SRAM_LENGTH (32 * 1024)
#define FLASHRAM_LENGTH (128 * 1024)
#define SRAM_BANKED_LENGTH (3 * 32 * 1024)
#define SRAM_1M_LENGTH (128 * 1024)
#define WRITEBACK_DELAY_TICKS (100)
#define SAVE_MAX_SECTOR_COUNT (256)
#define EEPROM_ADDRESS (0x05002000)
#define SRAM_FLASHRAM_ADDRESS (0x03FE0000)
#define EEPROM_4K_LENGTH (512)
#define EEPROM_16K_LENGTH (2048)
#define SRAM_LENGTH (32 * 1024)
#define FLASHRAM_LENGTH (128 * 1024)
#define SRAM_BANKED_LENGTH (3 * 32 * 1024)
#define SRAM_1M_LENGTH (128 * 1024)
#define WRITEBACK_DELAY_MS (1000)
struct process {
@ -111,6 +114,7 @@ void writeback_load_sector_table (uint32_t address) {
}
}
void writeback_enable (writeback_mode_t mode) {
p.enabled = true;
p.pending = false;
@ -121,13 +125,14 @@ void writeback_enable (writeback_mode_t mode) {
void writeback_disable (void) {
p.enabled = false;
p.pending = false;
timer_set(TIMER_ID_WRITEBACK, 0);
timer_countdown_abort(TIMER_ID_WRITEBACK);
}
bool writeback_pending (void) {
return p.enabled && p.pending;
}
void writeback_init (void) {
p.enabled = false;
p.pending = false;
@ -137,6 +142,7 @@ void writeback_init (void) {
}
}
void writeback_process (void) {
if (p.enabled && (p.mode == WRITEBACK_SD) && !sd_card_is_inserted()) {
writeback_disable();
@ -144,24 +150,27 @@ void writeback_process (void) {
if (p.enabled) {
uint16_t save_count = fpga_reg_get(REG_SAVE_COUNT);
if (save_count != p.last_save_count) {
p.pending = true;
p.last_save_count = save_count;
timer_set(TIMER_ID_WRITEBACK, WRITEBACK_DELAY_TICKS);
timer_countdown_start(TIMER_ID_WRITEBACK, WRITEBACK_DELAY_MS);
}
}
if (p.pending && (timer_get(TIMER_ID_WRITEBACK) == 0)) {
if (p.pending && timer_countdown_elapsed(TIMER_ID_WRITEBACK)) {
switch (p.mode) {
case WRITEBACK_SD:
writeback_save_to_sd();
p.pending = false;
break;
case WRITEBACK_USB:
if (writeback_save_to_usb()) {
p.pending = false;
}
break;
default:
writeback_disable();
break;

View File

@ -6,7 +6,7 @@
#include <stdint.h>
#define WRITEBACK_SECTOR_TABLE_SIZE (1024)
#define WRITEBACK_SECTOR_TABLE_SIZE (1024)
typedef enum {
@ -16,10 +16,13 @@ typedef enum {
void writeback_load_sector_table (uint32_t address);
void writeback_enable (writeback_mode_t mode);
void writeback_disable (void);
bool writeback_pending (void);
void writeback_init (void);
void writeback_process (void);