[SC64][FW][SW] Controller rewrite to remove task subsystem + minor bug fixes (#64)

This PR completely removes `task.c / task.h` from `sw/controller` STM32
code.
Additionally, these changes were implemented:
- Updated IPL3
- Added new diagnostic data (voltage and temperature) readout commands
for USB and N64
- Fixed some issues with FlashRAM save type
- Joybus timings were relaxed to accommodate communication with
unsynchronized master controller (like _Datel Game Killer_, thanks
@RWeick)
- N64 embedded test program now waits for release of button press to
proceed
- Fixed issue where, in rare circumstances, I2C peripheral in STM32
would get locked-up on power-up
- LED blinking behavior on SD card access was changed
- LED blink duration on save writeback has been extended
- Minor fixes through the entire of hardware abstraction layer for STM32
code
- Primer now correctly detects issues with I2C bus during first time
programming
- `primer.py` script gives more meaningful error messages
- Fixed bug where RTC time was always written on N64FlashcartMenu boot
- sc64deployer now displays "Diagnostic data" instead of "MCU stack
usage"
This commit is contained in:
Mateusz Faderewski 2024-01-29 14:23:18 +01:00 committed by GitHub
parent be37025d42
commit 421d0438f3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
62 changed files with 1837 additions and 1994 deletions

View File

@ -83,6 +83,8 @@ build_cic () {
build_fpga () { build_fpga () {
if [ "$BUILT_FPGA" = true ]; then return; fi if [ "$BUILT_FPGA" = true ]; then return; fi
build_cic
pushd fw/project/lcmxo2 > /dev/null pushd fw/project/lcmxo2 > /dev/null
if [ "$FORCE_CLEAN" = true ]; then if [ "$FORCE_CLEAN" = true ]; then
rm -rf ./impl1/ rm -rf ./impl1/

View File

@ -1,6 +1,6 @@
#!/bin/bash #!/bin/bash
BUILDER_IMAGE="ghcr.io/polprzewodnikowy/sc64env:v1.8" BUILDER_IMAGE="ghcr.io/polprzewodnikowy/sc64env:v1.9"
pushd $(dirname $0) > /dev/null pushd $(dirname $0) > /dev/null

View File

@ -5,7 +5,7 @@
## N64 commands ## N64 commands
| id | name | arg0 | arg1 | rsp0 | rsp1 | description | | id | name | arg0 | arg1 | rsp0 | rsp1 | description |
| --- | --------------------- | -------------- | ------------ | ---------------- | -------------- | ---------------------------------------------------------- | | --- | --------------------- | ------------- | ------------ | ---------------- | -------------- | ---------------------------------------------------------- |
| `v` | **IDENTIFIER_GET** | --- | --- | identifier | --- | Get flashcart identifier `SCv2` | | `v` | **IDENTIFIER_GET** | --- | --- | identifier | --- | Get flashcart identifier `SCv2` |
| `V` | **VERSION_GET** | --- | --- | major/minor | revision | Get flashcart firmware version | | `V` | **VERSION_GET** | --- | --- | major/minor | revision | Get flashcart firmware version |
| `c` | **CONFIG_GET** | config_id | --- | --- | current_value | Get config option | | `c` | **CONFIG_GET** | config_id | --- | --- | current_value | Get config option |
@ -28,3 +28,4 @@
| `K` | **FLASH_PROGRAM** | pi_address | length | --- | --- | Program flash with bytes loaded into data buffer | | `K` | **FLASH_PROGRAM** | pi_address | length | --- | --- | Program flash with bytes loaded into data buffer |
| `p` | **FLASH_WAIT_BUSY** | wait | --- | erase_block_size | --- | Wait until flash ready / get block erase size | | `p` | **FLASH_WAIT_BUSY** | wait | --- | erase_block_size | --- | Wait until flash ready / get block erase size |
| `P` | **FLASH_ERASE_BLOCK** | pi_address | --- | --- | --- | Start flash block erase | | `P` | **FLASH_ERASE_BLOCK** | pi_address | --- | --- | --- | Start flash block erase |
| `%` | **DIAGNOSTIC_GET** | diagnostic_id | --- | --- | value | Get diagnostic data |

View File

@ -170,7 +170,7 @@ Available packet IDs are listed in the [asynchronous packets](#asynchronous-pack
| `f` | **FIRMWARE_BACKUP** | address | --- | --- | status/length | Backup firmware to specified memory address | | `f` | **FIRMWARE_BACKUP** | address | --- | --- | status/length | Backup firmware to specified memory address |
| `F` | **FIRMWARE_UPDATE** | address | length | --- | status | Update firmware from specified memory address | | `F` | **FIRMWARE_UPDATE** | address | length | --- | status | Update firmware from specified memory address |
| `?` | **DEBUG_GET** | --- | --- | --- | debug_data | Get internal FPGA debug info | | `?` | **DEBUG_GET** | --- | --- | --- | debug_data | Get internal FPGA debug info |
| `%` | **STACK_USAGE_GET** | --- | --- | --- | stack_usage | Get per task stack usage | | `%` | **DIAGNOSTIC_GET** | --- | --- | --- | diagnostic_data | Get diagnostic data |
--- ---

View File

@ -474,7 +474,7 @@ module mcu_top (
18'd0, 18'd0,
n64_scb.flashram_write_or_erase, n64_scb.flashram_write_or_erase,
n64_scb.flashram_sector_or_all, n64_scb.flashram_sector_or_all,
n64_scb.flashram_sector, n64_scb.flashram_page,
n64_scb.flashram_pending, n64_scb.flashram_pending,
1'b0 1'b0
}; };

View File

@ -8,7 +8,7 @@ module n64_flashram (
); );
localparam [31:0] FLASH_TYPE_ID = 32'h1111_8001; localparam [31:0] FLASH_TYPE_ID = 32'h1111_8001;
localparam [31:0] FLASH_MODEL_ID = 32'h00C2_001D; localparam [31:0] FLASH_MODEL_ID = 32'h0032_00F1;
typedef enum bit [7:0] { typedef enum bit [7:0] {
CMD_STATUS_MODE = 8'hD2, CMD_STATUS_MODE = 8'hD2,
@ -97,14 +97,14 @@ module n64_flashram (
CMD_ERASE_SECTOR: begin CMD_ERASE_SECTOR: begin
state <= STATE_STATUS; state <= STATE_STATUS;
erase_enabled <= 1'b1; erase_enabled <= 1'b1;
n64_scb.flashram_sector <= reg_bus.wdata[9:0]; n64_scb.flashram_page <= reg_bus.wdata[9:0];
n64_scb.flashram_sector_or_all <= 1'b0; n64_scb.flashram_sector_or_all <= 1'b0;
end end
CMD_ERASE_CHIP: begin CMD_ERASE_CHIP: begin
state <= STATE_STATUS; state <= STATE_STATUS;
erase_enabled <= 1'b1; erase_enabled <= 1'b1;
n64_scb.flashram_sector <= 10'd0; n64_scb.flashram_page <= 10'd0;
n64_scb.flashram_sector_or_all <= 1'b1; n64_scb.flashram_sector_or_all <= 1'b1;
end end
@ -126,7 +126,7 @@ module n64_flashram (
state <= STATE_STATUS; state <= STATE_STATUS;
status[WRITE_BUSY] <= 1'b1; status[WRITE_BUSY] <= 1'b1;
status[WRITE_DONE] <= 1'b0; status[WRITE_DONE] <= 1'b0;
n64_scb.flashram_sector <= reg_bus.wdata[9:0]; n64_scb.flashram_page <= reg_bus.wdata[9:0];
n64_scb.flashram_pending <= 1'b1; n64_scb.flashram_pending <= 1'b1;
n64_scb.flashram_write_or_erase <= 1'b0; n64_scb.flashram_write_or_erase <= 1'b0;
n64_scb.flashram_sector_or_all <= 1'b0; n64_scb.flashram_sector_or_all <= 1'b0;
@ -134,9 +134,9 @@ module n64_flashram (
endcase endcase
end end
end else begin end else begin
if (reg_bus.address[1] && state != STATE_BUFFER) begin if (reg_bus.address[1] && state == STATE_STATUS) begin
status[ERASE_BUSY] <= reg_bus.wdata[ERASE_BUSY]; status[ERASE_DONE] <= 1'b0;
status[WRITE_BUSY] <= reg_bus.wdata[WRITE_BUSY]; status[WRITE_DONE] <= 1'b0;
end end
end end
end end

View File

@ -22,7 +22,7 @@ interface n64_scb ();
logic flashram_pending; logic flashram_pending;
logic flashram_done; logic flashram_done;
logic [9:0] flashram_sector; logic [9:0] flashram_page;
logic flashram_sector_or_all; logic flashram_sector_or_all;
logic flashram_write_or_erase; logic flashram_write_or_erase;
logic flashram_read_mode; logic flashram_read_mode;
@ -84,7 +84,7 @@ interface n64_scb ();
input flashram_pending, input flashram_pending,
output flashram_done, output flashram_done,
input flashram_sector, input flashram_page,
input flashram_sector_or_all, input flashram_sector_or_all,
input flashram_write_or_erase, input flashram_write_or_erase,
@ -143,7 +143,7 @@ interface n64_scb ();
modport flashram ( modport flashram (
output flashram_pending, output flashram_pending,
input flashram_done, input flashram_done,
output flashram_sector, output flashram_page,
output flashram_sector_or_all, output flashram_sector_or_all,
output flashram_write_or_erase, output flashram_write_or_erase,

View File

@ -59,6 +59,7 @@ module n64_si (
// Data falling/rising event generator // Data falling/rising event generator
logic last_si_dq_in; logic last_si_dq_in;
logic si_dq_in_inhibit;
always_ff @(posedge clk) begin always_ff @(posedge clk) begin
if (si_clk_rising_edge) begin if (si_clk_rising_edge) begin
@ -70,14 +71,14 @@ module n64_si (
logic si_dq_rising_edge; logic si_dq_rising_edge;
always_comb begin always_comb begin
si_dq_falling_edge = si_clk_rising_edge && last_si_dq_in && !si_dq_in; si_dq_falling_edge = si_clk_rising_edge && last_si_dq_in && !si_dq_in && !si_dq_in_inhibit;
si_dq_rising_edge = si_clk_rising_edge && !last_si_dq_in && si_dq_in; si_dq_rising_edge = si_clk_rising_edge && !last_si_dq_in && si_dq_in && !si_dq_in_inhibit;
end end
// RX bit generator // RX bit generator
logic [3:0] rx_sub_bit_counter; logic [4:0] rx_sub_bit_counter;
logic rx_timeout; logic rx_timeout;
logic rx_bit_valid; logic rx_bit_valid;
logic rx_bit_data; logic rx_bit_data;
@ -94,7 +95,7 @@ module n64_si (
always_comb begin always_comb begin
rx_timeout = si_clk_rising_edge && si_dq_in && (&rx_sub_bit_counter); rx_timeout = si_clk_rising_edge && si_dq_in && (&rx_sub_bit_counter);
rx_bit_valid = si_dq_rising_edge; rx_bit_valid = si_dq_rising_edge;
rx_bit_data = (rx_sub_bit_counter >= 4'd3) ? 1'b0 : 1'b1; rx_bit_data = (rx_sub_bit_counter >= 5'd4) ? 1'b0 : 1'b1;
end end
@ -124,7 +125,7 @@ module n64_si (
logic rx_stop; logic rx_stop;
always_comb begin always_comb begin
rx_stop = si_clk_rising_edge && si_dq_in && (rx_sub_bit_counter == 4'd7) && (rx_bit_counter == 3'd1); rx_stop = si_clk_rising_edge && si_dq_in && (rx_sub_bit_counter == 5'd15) && (rx_bit_counter == 3'd1);
end end
@ -260,7 +261,8 @@ module n64_si (
typedef enum bit [1:0] { typedef enum bit [1:0] {
TX_STATE_IDLE, TX_STATE_IDLE,
TX_STATE_DATA, TX_STATE_DATA,
TX_STATE_STOP TX_STATE_STOP,
TX_STATE_STOP_WAIT
} e_tx_state; } e_tx_state;
e_tx_state tx_state; e_tx_state tx_state;
@ -278,12 +280,14 @@ module n64_si (
if (reset) begin if (reset) begin
tx_state <= TX_STATE_IDLE; tx_state <= TX_STATE_IDLE;
si_dq_in_inhibit <= 1'b0;
end else begin end else begin
case (tx_state) case (tx_state)
TX_STATE_IDLE: begin TX_STATE_IDLE: begin
if (tx_start) begin if (tx_start) begin
tx_byte_counter <= 4'd0; tx_byte_counter <= 4'd0;
tx_state <= TX_STATE_DATA; tx_state <= TX_STATE_DATA;
si_dq_in_inhibit <= 1'b1;
end end
end end
@ -299,7 +303,14 @@ module n64_si (
TX_STATE_STOP: begin TX_STATE_STOP: begin
tx_stop <= 1'b1; tx_stop <= 1'b1;
if (!tx_busy && tx_stop) begin if (!tx_busy && tx_stop) begin
tx_state <= TX_STATE_STOP_WAIT;
end
end
TX_STATE_STOP_WAIT: begin
if (!tx_busy) begin
tx_state <= TX_STATE_IDLE; tx_state <= TX_STATE_IDLE;
si_dq_in_inhibit <= 1'b0;
end end
end end
endcase endcase
@ -382,7 +393,7 @@ module n64_si (
4'd1: {rtc_time_wp, rtc_backup_wp} <= rx_byte_data[1:0]; 4'd1: {rtc_time_wp, rtc_backup_wp} <= rx_byte_data[1:0];
4'd2: begin 4'd2: begin
rtc_stopped <= rx_byte_data[2:1]; 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; n64_scb.rtc_pending <= 1'b1;
end end
end end

View File

@ -68,7 +68,7 @@ const uint8_t font_data[96][FONT_CHAR_BYTES] = {
{ 0x38, 0x30, 0x30, 0x30, 0x30, 0x30, 0x38, 0x00, }, { 0x38, 0x30, 0x30, 0x30, 0x30, 0x30, 0x38, 0x00, },
{ 0x00, 0x38, 0x6C, 0x00, 0x00, 0x00, 0x00, 0x00, }, { 0x00, 0x38, 0x6C, 0x00, 0x00, 0x00, 0x00, 0x00, },
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, }, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, },
{ 0x00, 0x18, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, }, { 0x1C, 0x63, 0x63, 0x1C, 0x00, 0x00, 0x00, 0x00, },
{ 0x00, 0x3C, 0x60, 0x7C, 0x66, 0x66, 0x7C, 0x00, }, { 0x00, 0x3C, 0x60, 0x7C, 0x66, 0x66, 0x7C, 0x00, },
{ 0x06, 0x06, 0x3E, 0x66, 0x66, 0x66, 0x3E, 0x00, }, { 0x06, 0x06, 0x3E, 0x66, 0x66, 0x66, 0x3E, 0x00, },
{ 0x00, 0x3C, 0x66, 0x06, 0x06, 0x06, 0x7C, 0x00, }, { 0x00, 0x3C, 0x66, 0x06, 0x06, 0x06, 0x7C, 0x00, },

View File

@ -48,6 +48,7 @@ typedef enum {
CMD_ID_FLASH_PROGRAM = 'K', CMD_ID_FLASH_PROGRAM = 'K',
CMD_ID_FLASH_WAIT_BUSY = 'p', CMD_ID_FLASH_WAIT_BUSY = 'p',
CMD_ID_FLASH_ERASE_BLOCK = 'P', CMD_ID_FLASH_ERASE_BLOCK = 'P',
CMD_ID_DIAGNOSTIC_GET = '%',
} sc64_cmd_id_t; } sc64_cmd_id_t;
typedef enum { typedef enum {
@ -436,3 +437,14 @@ sc64_error_t sc64_flash_erase_block (void *address) {
}; };
return sc64_execute_cmd(&cmd); return sc64_execute_cmd(&cmd);
} }
sc64_error_t sc64_get_diagnostic (sc64_diagnostic_id_t id, uint32_t *value) {
sc64_cmd_t cmd = {
.id = CMD_ID_DIAGNOSTIC_GET,
.arg = { id }
};
sc64_error_t error = sc64_execute_cmd(&cmd);
*value = cmd.rsp[1];
return error;
}

View File

@ -93,6 +93,10 @@ typedef enum {
BUTTON_MODE_DD_DISK_SWAP, BUTTON_MODE_DD_DISK_SWAP,
} sc64_button_mode_t; } sc64_button_mode_t;
typedef enum {
DIAGNOSTIC_ID_VOLTAGE_TEMPERATURE,
} sc64_diagnostic_id_t;
typedef struct { typedef struct {
sc64_boot_mode_t boot_mode; sc64_boot_mode_t boot_mode;
sc64_cic_seed_t cic_seed; sc64_cic_seed_t cic_seed;
@ -174,5 +178,7 @@ sc64_error_t sc64_flash_wait_busy (void);
sc64_error_t sc64_flash_get_erase_block_size (size_t *erase_block_size); sc64_error_t sc64_flash_get_erase_block_size (size_t *erase_block_size);
sc64_error_t sc64_flash_erase_block (void *address); sc64_error_t sc64_flash_erase_block (void *address);
sc64_error_t sc64_get_diagnostic (sc64_diagnostic_id_t id, uint32_t *value);
#endif #endif

View File

@ -10,10 +10,22 @@
static void test_sc64_cfg (void) { static void test_sc64_cfg (void) {
sc64_error_t error; sc64_error_t error;
uint32_t button_state;
uint32_t identifier; uint32_t identifier;
uint16_t major; uint16_t major;
uint16_t minor; uint16_t minor;
uint32_t revision; uint32_t revision;
uint32_t tmp;
display_printf("Waiting for the button to be released... ");
do {
if ((error = sc64_get_config(CFG_ID_BUTTON_STATE, &button_state)) != SC64_OK) {
error_display("Command CONFIG_GET [BUTTON_STATE] failed: %d", error);
}
} while (button_state != 0);
display_printf("done\n\n");
if ((error = sc64_get_identifier(&identifier)) != SC64_OK) { if ((error = sc64_get_identifier(&identifier)) != SC64_OK) {
error_display("Command IDENTIFIER_GET failed: %d", error); error_display("Command IDENTIFIER_GET failed: %d", error);
@ -25,9 +37,19 @@ static void test_sc64_cfg (void) {
return; return;
} }
display_printf("Identifier: 0x%08X\n\n", identifier); if ((error = sc64_get_diagnostic(DIAGNOSTIC_ID_VOLTAGE_TEMPERATURE, &tmp)) != SC64_OK) {
error_display("Command DIAGNOSTIC_GET failed: %d", error);
return;
}
display_printf("SC64 firmware version: %d.%d.%d\n", major, minor, revision); uint16_t voltage = (uint16_t) (tmp >> 16);
int16_t temperature = (int16_t) (tmp & 0xFFFF);
display_printf("Identifier: 0x%08X\n", identifier);
display_printf("SC64 firmware version: %d.%d.%d\n\n", major, minor, revision);
display_printf("Voltage: %d.%03d V\n", (voltage / 1000), (voltage % 1000));
display_printf("Temperature: %d.%01d `C\n", (temperature / 10), (temperature % 10));
} }
static void test_rtc (void) { static void test_rtc (void) {
@ -233,7 +255,7 @@ bool test_check (void) {
error_display("Command CONFIG_GET [BUTTON_STATE] failed: %d", error); error_display("Command CONFIG_GET [BUTTON_STATE] failed: %d", error);
} }
return button_state != 0; return (button_state != 0);
} }
static struct { static struct {

View File

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

View File

@ -8,7 +8,7 @@
.type loader, %object .type loader, %object
loader: loader:
.incbin "build/loader/loader.bin" .incbin "build/loader/loader.bin"
.org 0x1000, 0xFF
.section .text.Reset_Handler .section .text.Reset_Handler
.type Reset_Handler, %function .type Reset_Handler, %function

View File

@ -1,34 +1,51 @@
#include "app.h" #include <stdbool.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 "hw.h"
#include "isv.h"
#include "led.h" #include "led.h"
#include "rtc.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) { void app (void) {
hw_init(); hw_app_init();
task_create(TASK_ID_RTC, rtc_task, rtc_stack, RTC_STACK_SIZE); timer_init();
task_create(TASK_ID_LED, led_task, led_stack, LED_STACK_SIZE);
task_create(TASK_ID_GVR, gvr_task, gvr_stack, GVR_STACK_SIZE);
task_scheduler_start(); while (fpga_id_get() != FPGA_ID);
rtc_init();
button_init();
cfg_init();
cic_init();
dd_init();
flashram_init();
isv_init();
led_init();
sd_init();
usb_init();
writeback_init();
while (true) {
button_process();
cfg_process();
cic_process();
dd_process();
flashram_process();
isv_process();
led_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

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

View File

@ -6,17 +6,20 @@
typedef enum { typedef enum {
BUTTON_MODE_NONE, BUTTON_MODE_NONE = 0,
BUTTON_MODE_N64_IRQ, BUTTON_MODE_N64_IRQ = 1,
BUTTON_MODE_USB_PACKET, BUTTON_MODE_USB_PACKET = 2,
BUTTON_MODE_DD_DISK_SWAP, BUTTON_MODE_DD_DISK_SWAP = 3,
__BUTTON_MODE_COUNT
} button_mode_t; } button_mode_t;
bool button_get_state (void); bool button_get_state (void);
bool button_set_mode (button_mode_t mode); bool button_set_mode (button_mode_t mode);
button_mode_t button_get_mode (void); button_mode_t button_get_mode (void);
void button_init (void); void button_init (void);
void button_process (void); void button_process (void);

View File

@ -4,7 +4,9 @@
#include "dd.h" #include "dd.h"
#include "flash.h" #include "flash.h"
#include "fpga.h" #include "fpga.h"
#include "hw.h"
#include "isv.h" #include "isv.h"
#include "led.h"
#include "rtc.h" #include "rtc.h"
#include "sd.h" #include "sd.h"
#include "usb.h" #include "usb.h"
@ -17,25 +19,25 @@
typedef enum { typedef enum {
CFG_ID_BOOTLOADER_SWITCH, CFG_ID_BOOTLOADER_SWITCH = 0,
CFG_ID_ROM_WRITE_ENABLE, CFG_ID_ROM_WRITE_ENABLE = 1,
CFG_ID_ROM_SHADOW_ENABLE, CFG_ID_ROM_SHADOW_ENABLE = 2,
CFG_ID_DD_MODE, CFG_ID_DD_MODE = 3,
CFG_ID_ISV_ADDRESS, CFG_ID_ISV_ADDRESS = 4,
CFG_ID_BOOT_MODE, CFG_ID_BOOT_MODE = 5,
CFG_ID_SAVE_TYPE, CFG_ID_SAVE_TYPE = 6,
CFG_ID_CIC_SEED, CFG_ID_CIC_SEED = 7,
CFG_ID_TV_TYPE, CFG_ID_TV_TYPE = 8,
CFG_ID_DD_SD_ENABLE, CFG_ID_DD_SD_ENABLE = 9,
CFG_ID_DD_DRIVE_TYPE, CFG_ID_DD_DRIVE_TYPE = 10,
CFG_ID_DD_DISK_STATE, CFG_ID_DD_DISK_STATE = 11,
CFG_ID_BUTTON_STATE, CFG_ID_BUTTON_STATE = 12,
CFG_ID_BUTTON_MODE, CFG_ID_BUTTON_MODE = 13,
CFG_ID_ROM_EXTENDED_ENABLE, CFG_ID_ROM_EXTENDED_ENABLE = 14,
} cfg_id_t; } cfg_id_t;
typedef enum { typedef enum {
SETTING_ID_LED_ENABLE, SETTING_ID_LED_ENABLE = 0,
} setting_id_t; } setting_id_t;
typedef enum { typedef enum {
@ -83,6 +85,10 @@ typedef enum {
SD_CARD_OP_BYTE_SWAP_OFF = 5, SD_CARD_OP_BYTE_SWAP_OFF = 5,
} sd_card_op_t; } sd_card_op_t;
typedef enum {
DIAGNOSTIC_ID_VOLTAGE_TEMPERATURE = 0,
} diagnostic_id_t;
typedef enum { typedef enum {
SDRAM = (1 << 0), SDRAM = (1 << 0),
FLASH = (1 << 1), FLASH = (1 << 1),
@ -178,7 +184,7 @@ static void cfg_change_scr_bits (uint32_t mask, bool value) {
} }
static bool cfg_set_save_type (save_type_t save_type) { static bool cfg_set_save_type (save_type_t save_type) {
if (save_type > SAVE_TYPE_SRAM_1M) { if (save_type >= __SAVE_TYPE_COUNT) {
return true; return true;
} }
@ -225,6 +231,22 @@ static bool cfg_set_save_type (save_type_t save_type) {
return false; return false;
} }
static bool cfg_read_diagnostic_data (uint32_t *args) {
switch (args[0]) {
case DIAGNOSTIC_ID_VOLTAGE_TEMPERATURE: {
uint16_t voltage;
int16_t temperature;
hw_adc_read_voltage_temperature(&voltage, &temperature);
args[1] = ((uint32_t) (voltage) << 16) | ((uint32_t) (temperature));
break;
}
default:
return true;
}
return false;
}
uint32_t cfg_get_identifier (void) { uint32_t cfg_get_identifier (void) {
return fpga_reg_get(REG_CFG_IDENTIFIER); return fpga_reg_get(REG_CFG_IDENTIFIER);
@ -373,11 +395,11 @@ bool cfg_update (uint32_t *args) {
} }
bool cfg_query_setting (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]) { switch (args[0]) {
case SETTING_ID_LED_ENABLE: case SETTING_ID_LED_ENABLE:
args[1] = settings.led_enabled; args[1] = settings->led_enabled;
break; break;
default: default:
return true; return true;
@ -387,17 +409,17 @@ bool cfg_query_setting (uint32_t *args) {
} }
bool cfg_update_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]) { switch (args[0]) {
case SETTING_ID_LED_ENABLE: case SETTING_ID_LED_ENABLE:
settings.led_enabled = args[1]; settings->led_enabled = args[1];
break; break;
default: default:
return true; return true;
} }
rtc_set_settings(&settings); rtc_save_settings();
return false; return false;
} }
@ -450,12 +472,14 @@ void cfg_reset_state (void) {
p.boot_mode = BOOT_MODE_MENU; p.boot_mode = BOOT_MODE_MENU;
} }
void cfg_init (void) { void cfg_init (void) {
fpga_reg_set(REG_CFG_SCR, CFG_SCR_BOOTLOADER_ENABLED); fpga_reg_set(REG_CFG_SCR, CFG_SCR_BOOTLOADER_ENABLED);
cfg_reset_state(); cfg_reset_state();
p.usb_output_ready = true; p.usb_output_ready = true;
} }
void cfg_process (void) { void cfg_process (void) {
uint32_t reg; uint32_t reg;
uint32_t args[2]; uint32_t args[2];
@ -558,12 +582,16 @@ void cfg_process (void) {
case SD_CARD_OP_DEINIT: case SD_CARD_OP_DEINIT:
sd_card_deinit(); sd_card_deinit();
break; break;
case SD_CARD_OP_INIT: case SD_CARD_OP_INIT: {
if (sd_card_init()) { led_activity_on();
bool error = sd_card_init();
led_activity_off();
if (error) {
cfg_set_error(CFG_ERROR_SD_CARD); cfg_set_error(CFG_ERROR_SD_CARD);
return; return;
} }
break; break;
}
case SD_CARD_OP_GET_STATUS: case SD_CARD_OP_GET_STATUS:
args[1] = sd_card_get_status(); args[1] = sd_card_get_status();
break; break;
@ -599,7 +627,7 @@ void cfg_process (void) {
p.sd_card_sector = args[0]; p.sd_card_sector = args[0];
break; break;
case 's': case 's': {
if (args[1] >= 0x800000) { if (args[1] >= 0x800000) {
cfg_set_error(CFG_ERROR_BAD_ARGUMENT); cfg_set_error(CFG_ERROR_BAD_ARGUMENT);
return; return;
@ -608,14 +636,18 @@ void cfg_process (void) {
cfg_set_error(CFG_ERROR_BAD_ADDRESS); cfg_set_error(CFG_ERROR_BAD_ADDRESS);
return; return;
} }
if (sd_read_sectors(args[0], p.sd_card_sector, args[1])) { led_activity_on();
bool error = sd_read_sectors(args[0], p.sd_card_sector, args[1]);
led_activity_off();
if (error) {
cfg_set_error(CFG_ERROR_SD_CARD); cfg_set_error(CFG_ERROR_SD_CARD);
return; return;
} }
p.sd_card_sector += args[1]; p.sd_card_sector += args[1];
break; break;
}
case 'S': case 'S': {
if (args[1] >= 0x800000) { if (args[1] >= 0x800000) {
cfg_set_error(CFG_ERROR_BAD_ARGUMENT); cfg_set_error(CFG_ERROR_BAD_ARGUMENT);
return; return;
@ -624,12 +656,16 @@ void cfg_process (void) {
cfg_set_error(CFG_ERROR_BAD_ADDRESS); cfg_set_error(CFG_ERROR_BAD_ADDRESS);
return; return;
} }
if (sd_write_sectors(args[0], p.sd_card_sector, args[1])) { led_activity_on();
bool error = sd_write_sectors(args[0], p.sd_card_sector, args[1]);
led_activity_off();
if (error) {
cfg_set_error(CFG_ERROR_SD_CARD); cfg_set_error(CFG_ERROR_SD_CARD);
return; return;
} }
p.sd_card_sector += args[1]; p.sd_card_sector += args[1];
break; break;
}
case 'D': case 'D':
if (cfg_translate_address(&args[0], args[1], (SDRAM | BRAM))) { if (cfg_translate_address(&args[0], args[1], (SDRAM | BRAM))) {
@ -685,6 +721,13 @@ void cfg_process (void) {
} }
break; break;
case '%':
if (cfg_read_diagnostic_data(args)) {
cfg_set_error(CFG_ERROR_BAD_CONFIG_ID);
return;
}
break;
default: default:
cfg_set_error(CFG_ERROR_UNKNOWN_CMD); cfg_set_error(CFG_ERROR_UNKNOWN_CMD);
return; return;

View File

@ -14,6 +14,7 @@ typedef enum {
SAVE_TYPE_FLASHRAM = 4, SAVE_TYPE_FLASHRAM = 4,
SAVE_TYPE_SRAM_BANKED = 5, SAVE_TYPE_SRAM_BANKED = 5,
SAVE_TYPE_SRAM_1M = 6, SAVE_TYPE_SRAM_1M = 6,
__SAVE_TYPE_COUNT
} save_type_t; } save_type_t;
@ -27,7 +28,9 @@ save_type_t cfg_get_save_type (void);
void cfg_get_time (uint32_t *args); void cfg_get_time (uint32_t *args);
void cfg_set_time (uint32_t *args); void cfg_set_time (uint32_t *args);
void cfg_reset_state (void); void cfg_reset_state (void);
void cfg_init (void); void cfg_init (void);
void cfg_process (void); void cfg_process (void);

View File

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

View File

@ -1,10 +1,9 @@
#include <stdint.h>
#include "dd.h" #include "dd.h"
#include "fpga.h" #include "fpga.h"
#include "hw.h"
#include "led.h" #include "led.h"
#include "rtc.h" #include "rtc.h"
#include "sd.h" #include "sd.h"
#include "timer.h"
#include "usb.h" #include "usb.h"
@ -20,7 +19,7 @@
#define DD_DRIVE_ID_DEVELOPMENT (0x0004) #define DD_DRIVE_ID_DEVELOPMENT (0x0004)
#define DD_VERSION_RETAIL (0x0114) #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_UNMAPPED (0xFFFFFFFF)
#define DD_THB_WRITABLE_FLAG (1 << 31) #define DD_THB_WRITABLE_FLAG (1 << 31)
@ -75,7 +74,6 @@ struct process {
rtc_time_t time; rtc_time_t time;
bool disk_spinning; bool disk_spinning;
bool cmd_response_delayed; bool cmd_response_delayed;
bool cmd_response_ready;
bool bm_running; bool bm_running;
bool transfer_mode; bool transfer_mode;
bool full_track_transfer; bool full_track_transfer;
@ -138,7 +136,9 @@ static bool dd_block_read_request (void) {
if (p.sd_mode) { if (p.sd_mode) {
uint32_t sector_table[DD_SD_SECTOR_TABLE_SIZE]; uint32_t sector_table[DD_SD_SECTOR_TABLE_SIZE];
uint32_t sectors = dd_fill_sd_sector_table(index, sector_table, false); uint32_t sectors = dd_fill_sd_sector_table(index, sector_table, false);
led_activity_on();
bool error = sd_optimize_sectors(buffer_address, sector_table, sectors, sd_read_sectors); bool error = sd_optimize_sectors(buffer_address, sector_table, sectors, sd_read_sectors);
led_activity_off();
dd_set_block_ready(!error); dd_set_block_ready(!error);
} else { } else {
usb_tx_info_t packet_info; usb_tx_info_t packet_info;
@ -160,7 +160,9 @@ static bool dd_block_write_request (void) {
if (p.sd_mode) { if (p.sd_mode) {
uint32_t sector_table[DD_SD_SECTOR_TABLE_SIZE]; uint32_t sector_table[DD_SD_SECTOR_TABLE_SIZE];
uint32_t sectors = dd_fill_sd_sector_table(index, sector_table, true); uint32_t sectors = dd_fill_sd_sector_table(index, sector_table, true);
led_activity_on();
bool error = sd_optimize_sectors(buffer_address, sector_table, sectors, sd_write_sectors); bool error = sd_optimize_sectors(buffer_address, sector_table, sectors, sd_write_sectors);
led_activity_off();
dd_set_block_ready(!error); dd_set_block_ready(!error);
} else { } else {
usb_tx_info_t packet_info; usb_tx_info_t packet_info;
@ -178,10 +180,6 @@ static bool dd_block_write_request (void) {
return true; return true;
} }
static void dd_set_cmd_response_ready (void) {
p.cmd_response_ready = true;
}
void dd_set_block_ready (bool valid) { void dd_set_block_ready (bool valid) {
p.block_ready = true; p.block_ready = true;
@ -269,7 +267,7 @@ void dd_set_disk_mapping (uint32_t address, uint32_t length) {
} }
void dd_handle_button (void) { void dd_handle_button (void) {
led_blink_act(); led_activity_pulse();
if (dd_get_disk_state() == DD_DISK_STATE_EJECTED) { if (dd_get_disk_state() == DD_DISK_STATE_EJECTED) {
dd_set_disk_state(DD_DISK_STATE_INSERTED); dd_set_disk_state(DD_DISK_STATE_INSERTED);
} else { } else {
@ -284,13 +282,13 @@ void dd_handle_button (void) {
} }
} }
void dd_init (void) { void dd_init (void) {
fpga_reg_set(REG_DD_SCR, 0); fpga_reg_set(REG_DD_SCR, 0);
fpga_reg_set(REG_DD_HEAD_TRACK, 0); fpga_reg_set(REG_DD_HEAD_TRACK, 0);
fpga_reg_set(REG_DD_DRIVE_ID, DD_DRIVE_ID_RETAIL); fpga_reg_set(REG_DD_DRIVE_ID, DD_DRIVE_ID_RETAIL);
p.state = STATE_IDLE; p.state = STATE_IDLE;
p.cmd_response_delayed = false; p.cmd_response_delayed = false;
p.cmd_response_ready = false;
p.disk_spinning = false; p.disk_spinning = false;
p.bm_running = false; p.bm_running = false;
p.drive_type = DD_DRIVE_TYPE_RETAIL; p.drive_type = DD_DRIVE_TYPE_RETAIL;
@ -299,6 +297,7 @@ void dd_init (void) {
dd_set_disk_mapping(0, 0); dd_set_disk_mapping(0, 0);
} }
void dd_process (void) { void dd_process (void) {
uint32_t starting_scr = fpga_reg_get(REG_DD_SCR); uint32_t starting_scr = fpga_reg_get(REG_DD_SCR);
uint32_t scr = starting_scr; uint32_t scr = starting_scr;
@ -306,7 +305,6 @@ void dd_process (void) {
if (scr & DD_SCR_HARD_RESET) { if (scr & DD_SCR_HARD_RESET) {
p.state = STATE_IDLE; p.state = STATE_IDLE;
p.cmd_response_delayed = false; p.cmd_response_delayed = false;
p.cmd_response_ready = false;
p.disk_spinning = false; p.disk_spinning = false;
p.bm_running = false; p.bm_running = false;
p.head_track = 0; p.head_track = 0;
@ -319,19 +317,16 @@ void dd_process (void) {
uint16_t data = cmd_data & 0xFFFF; uint16_t data = cmd_data & 0xFFFF;
if (p.cmd_response_delayed) { if (p.cmd_response_delayed) {
if (p.cmd_response_ready) { if (timer_countdown_elapsed(TIMER_ID_DD)) {
p.cmd_response_delayed = false; p.cmd_response_delayed = false;
fpga_reg_set(REG_DD_HEAD_TRACK, DD_HEAD_TRACK_INDEX_LOCK | data); fpga_reg_set(REG_DD_HEAD_TRACK, DD_HEAD_TRACK_INDEX_LOCK | data);
scr |= DD_SCR_CMD_READY; scr |= DD_SCR_CMD_READY;
} }
} else if ((cmd == DD_CMD_SEEK_READ) || (cmd == DD_CMD_SEEK_WRITE)) { } else if ((cmd == DD_CMD_SEEK_READ) || (cmd == DD_CMD_SEEK_WRITE)) {
p.cmd_response_delayed = true; p.cmd_response_delayed = true;
p.cmd_response_ready = false;
if (!p.disk_spinning) { if (!p.disk_spinning) {
p.disk_spinning = true; p.disk_spinning = true;
hw_tim_setup(TIM_ID_DD, DD_SPIN_UP_TIME, dd_set_cmd_response_ready); timer_countdown_start(TIMER_ID_DD, DD_SPIN_UP_TIME_MS);
} else {
p.cmd_response_ready = true;
} }
fpga_reg_set(REG_DD_HEAD_TRACK, p.head_track & ~(DD_HEAD_TRACK_INDEX_LOCK)); fpga_reg_set(REG_DD_HEAD_TRACK, p.head_track & ~(DD_HEAD_TRACK_INDEX_LOCK));
p.head_track = data & DD_HEAD_TRACK_MASK; 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_sd_mode (bool value);
void dd_set_disk_mapping (uint32_t address, uint32_t length); void dd_set_disk_mapping (uint32_t address, uint32_t length);
void dd_handle_button (void); void dd_handle_button (void);
void dd_init (void); void dd_init (void);
void dd_process (void); void dd_process (void);

View File

@ -9,15 +9,15 @@
#define FLASHRAM_BUFFER_ADDRESS (0x05002900UL) #define FLASHRAM_BUFFER_ADDRESS (0x05002900UL)
enum operation { typedef enum {
OP_NONE, OP_NONE,
OP_ERASE_ALL, OP_ERASE_ALL,
OP_ERASE_SECTOR, OP_ERASE_SECTOR,
OP_WRITE_PAGE OP_WRITE_PAGE
}; } flashram_op_t;
static enum operation flashram_operation_type (uint32_t scr) { static flashram_op_t flashram_operation_type (uint32_t scr) {
if (!(scr & FLASHRAM_SCR_PENDING)) { if (!(scr & FLASHRAM_SCR_PENDING)) {
return OP_NONE; return OP_NONE;
} }
@ -40,40 +40,47 @@ void flashram_init (void) {
} }
} }
void flashram_process (void) { void flashram_process (void) {
uint32_t scr = fpga_reg_get(REG_FLASHRAM_SCR); 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 write_buffer[FLASHRAM_PAGE_SIZE];
uint32_t address = FLASHRAM_ADDRESS;
uint32_t erase_size = (op == OP_ERASE_SECTOR) ? FLASHRAM_SECTOR_SIZE : FLASHRAM_SIZE;
uint32_t page = (op != OP_ERASE_ALL) ? ((scr & FLASHRAM_SCR_PAGE_MASK) >> FLASHRAM_SCR_PAGE_BIT) : 0;
address += page * FLASHRAM_PAGE_SIZE;
switch (op) { flashram_op_t op = flashram_operation_type(scr);
case OP_ERASE_ALL:
case OP_ERASE_SECTOR: if (op == OP_NONE) {
return;
}
uint8_t write_buffer[FLASHRAM_PAGE_SIZE];
uint32_t page = ((scr & FLASHRAM_SCR_PAGE_MASK) >> FLASHRAM_SCR_PAGE_BIT);
if (op == OP_WRITE_PAGE) {
uint8_t page_buffer[FLASHRAM_PAGE_SIZE];
uint32_t address = (FLASHRAM_ADDRESS + (page * FLASHRAM_PAGE_SIZE));
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] &= page_buffer[i];
}
fpga_mem_write(address, FLASHRAM_PAGE_SIZE, write_buffer);
} else if ((op == OP_ERASE_SECTOR) || (op == OP_ERASE_ALL)) {
for (int i = 0; i < FLASHRAM_PAGE_SIZE; i++) { for (int i = 0; i < FLASHRAM_PAGE_SIZE; i++) {
write_buffer[i] = 0xFF; write_buffer[i] = 0xFF;
} }
for (int i = 0; i < erase_size; i += FLASHRAM_PAGE_SIZE) {
fpga_mem_write(address + i, FLASHRAM_PAGE_SIZE, write_buffer);
}
fpga_reg_set(REG_FLASHRAM_SCR, FLASHRAM_SCR_DONE);
break;
case OP_WRITE_PAGE: page &= ~((FLASHRAM_SECTOR_SIZE / FLASHRAM_PAGE_SIZE) - 1);
fpga_mem_read(FLASHRAM_BUFFER_ADDRESS, FLASHRAM_PAGE_SIZE, read_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];
}
fpga_mem_write(address, FLASHRAM_PAGE_SIZE, write_buffer);
fpga_reg_set(REG_FLASHRAM_SCR, FLASHRAM_SCR_DONE);
break;
case OP_NONE: uint32_t erase_size = (op == OP_ERASE_ALL) ? FLASHRAM_SIZE : FLASHRAM_SECTOR_SIZE;
default: uint32_t address = (FLASHRAM_ADDRESS + (page * FLASHRAM_PAGE_SIZE));
break;
for (uint32_t offset = 0; offset < erase_size; offset += FLASHRAM_PAGE_SIZE) {
fpga_mem_write(address + offset, 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_init (void);
void flashram_process (void); void flashram_process (void);

View File

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

@ -1,9 +1,134 @@
#include <stdbool.h>
#include <stddef.h> #include <stddef.h>
#include <stm32g0xx.h> #include <stm32g0xx.h>
#include "hw.h" #include "hw.h"
#define UART_BAUD (115200) #define CPU_FREQ (64000000UL)
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);
}
#define TIMEOUT_US_PER_TICK (10)
static void hw_timeout_init (void) {
RCC->APBENR1 |= RCC_APBENR1_DBGEN;
DBG->APBFZ2 |= DBG_APB_FZ2_DBG_TIM1_STOP;
RCC->APBENR2 |= RCC_APBENR2_TIM1EN;
TIM1->CR1 = TIM_CR1_OPM;
TIM1->PSC = (((CPU_FREQ / 1000 / 1000) * TIMEOUT_US_PER_TICK) - 1);
TIM1->EGR = TIM_EGR_UG;
}
static void hw_timeout_start (void) {
TIM1->CR1 &= ~(TIM_CR1_CEN);
TIM1->CNT = 0;
TIM1->CR1 |= TIM_CR1_CEN;
}
static bool hw_timeout_occured (uint32_t timeout_us) {
uint16_t count = TIM1->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_US_PER_TICK (1)
#define DELAY_MS_PER_TICK (1)
static void hw_delay_init (void) {
RCC->APBENR1 |= RCC_APBENR1_DBGEN;
DBG->APBFZ1 |= DBG_APB_FZ1_DBG_TIM3_STOP;
RCC->APBENR1 |= RCC_APBENR1_TIM3EN;
TIM3->CR1 = TIM_CR1_OPM;
TIM3->EGR = TIM_EGR_UG;
}
void hw_delay_us (uint32_t delay_us) {
TIM3->CR1 &= ~(TIM_CR1_CEN);
TIM3->PSC = (((CPU_FREQ / 1000 / 1000) * DELAY_US_PER_TICK) - 1);
TIM3->CNT = 0;
TIM3->EGR = TIM_EGR_UG;
TIM3->CR1 |= TIM_CR1_CEN;
uint32_t adjusted_delay = ((delay_us + (DELAY_US_PER_TICK - 1)) / DELAY_US_PER_TICK);
uint16_t count;
do {
count = TIM3->CNT;
} while ((count < adjusted_delay) && (count != 0xFFFF));
}
void hw_delay_ms (uint32_t delay_ms) {
TIM3->CR1 &= ~(TIM_CR1_CEN);
TIM3->PSC = (((CPU_FREQ / 1000) * DELAY_MS_PER_TICK) - 1);
TIM3->CNT = 0;
TIM3->EGR = TIM_EGR_UG;
TIM3->CR1 |= TIM_CR1_CEN;
uint32_t adjusted_delay = ((delay_ms + (DELAY_MS_PER_TICK - 1)) / DELAY_MS_PER_TICK);
uint16_t count;
do {
count = TIM3->CNT;
} while ((count < adjusted_delay) && (count != 0xFFFF));
}
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 { typedef enum {
@ -42,22 +167,7 @@ typedef enum {
GPIO_AF_7 = 0x07 GPIO_AF_7 = 0x07
} gpio_af_t; } 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 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) { 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; GPIO_TypeDef tmp;
@ -65,6 +175,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 pin = (id & 0x0F);
uint8_t afr = ((pin < 8) ? 0 : 1); 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.MODER = (gpio->MODER & ~(GPIO_MODER_MODE0_Msk << (pin * 2)));
tmp.OTYPER = (gpio->OTYPER & ~(GPIO_OTYPER_OT0_Msk << pin)); tmp.OTYPER = (gpio->OTYPER & ~(GPIO_OTYPER_OT0_Msk << pin));
tmp.OSPEEDR = (gpio->OSPEEDR & ~(GPIO_OSPEEDR_OSPEED0_Msk << (pin * 2))); tmp.OSPEEDR = (gpio->OSPEEDR & ~(GPIO_OSPEEDR_OSPEED0_Msk << (pin * 2)));
@ -80,22 +192,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))); 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) { uint32_t hw_gpio_get (gpio_id_t id) {
GPIO_TypeDef *gpio = ((GPIO_TypeDef *) (gpios[(id >> 4) & 0x07])); GPIO_TypeDef *gpio = ((GPIO_TypeDef *) (gpios[(id >> 4) & 0x07]));
uint8_t pin = (id & 0x0F); uint8_t pin = (id & 0x0F);
@ -114,6 +210,22 @@ void hw_gpio_reset (gpio_id_t id) {
gpio->BSRR = (GPIO_BSRR_BR0 << pin); gpio->BSRR = (GPIO_BSRR_BR0 << pin);
} }
#define UART_BAUD (115200UL)
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) { void hw_uart_read (uint8_t *data, int length) {
for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) {
while (!(USART1->ISR & USART_ISR_RXNE_RXFNE)); while (!(USART1->ISR & USART_ISR_RXNE_RXFNE));
@ -128,10 +240,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)); 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) { void hw_spi_start (void) {
hw_gpio_reset(GPIO_ID_SPI_CS); hw_gpio_reset(GPIO_ID_SPI_CS);
} }
@ -141,25 +285,17 @@ void hw_spi_stop (void) {
hw_gpio_set(GPIO_ID_SPI_CS); hw_gpio_set(GPIO_ID_SPI_CS);
} }
void hw_spi_trx (uint8_t *data, int length, spi_direction_t direction) { void hw_spi_rx (uint8_t *data, int length) {
volatile uint8_t dummy __attribute__((unused)); volatile uint8_t dummy = 0x00;
DMA1_Channel1->CNDTR = length; DMA1_Channel1->CNDTR = length;
DMA1_Channel2->CNDTR = length; DMA1_Channel2->CNDTR = length;
if (direction == SPI_TX) {
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);
} else {
DMA1_Channel1->CMAR = (uint32_t) (data); DMA1_Channel1->CMAR = (uint32_t) (data);
DMA1_Channel1->CCR = (DMA_CCR_MINC | DMA_CCR_EN); DMA1_Channel1->CCR = (DMA_CCR_MINC | DMA_CCR_EN);
DMA1_Channel2->CMAR = (uint32_t) (&dummy); DMA1_Channel2->CMAR = (uint32_t) (&dummy);
DMA1_Channel2->CCR = (DMA_CCR_DIR | DMA_CCR_EN); DMA1_Channel2->CCR = (DMA_CCR_DIR | DMA_CCR_EN);
}
while (DMA1_Channel1->CNDTR || DMA1_Channel2->CNDTR); while (DMA1_Channel1->CNDTR || DMA1_Channel2->CNDTR);
@ -167,160 +303,131 @@ void hw_spi_trx (uint8_t *data, int length, spi_direction_t direction) {
DMA1_Channel2->CCR = 0; DMA1_Channel2->CCR = 0;
} }
void hw_i2c_read (uint8_t i2c_address, uint8_t address, uint8_t *data, uint8_t length, void (*callback)(void)) { void hw_spi_tx (uint8_t *data, int length) {
i2c_data_rxptr = data; volatile uint8_t dummy __attribute__((unused));
i2c_callback = callback;
I2C1->TXDR = address; DMA1_Channel1->CNDTR = length;
i2c_next_cr2 = ( DMA1_Channel2->CNDTR = length;
I2C_CR2_AUTOEND |
(length << I2C_CR2_NBYTES_Pos) | DMA1_Channel1->CMAR = (uint32_t) (&dummy);
I2C_CR2_START | DMA1_Channel1->CCR = DMA_CCR_EN;
I2C_CR2_RD_WRN |
(i2c_address << I2C_CR2_SADD_Pos) DMA1_Channel2->CMAR = (uint32_t) (data);
); DMA1_Channel2->CCR = (DMA_CCR_MINC | DMA_CCR_DIR | DMA_CCR_EN);
I2C1->CR2 = (
(1 << I2C_CR2_NBYTES_Pos) | while (DMA1_Channel1->CNDTR || DMA1_Channel2->CNDTR);
I2C_CR2_START |
(i2c_address << I2C_CR2_SADD_Pos) 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; #define I2C_TIMEOUT_US_BUSY (10000)
i2c_callback = callback; #define I2C_TIMEOUT_US_PER_BYTE (1000)
I2C1->TXDR = address;
I2C1->CR2 = ( static void hw_i2c_init (void) {
I2C_CR2_AUTOEND | RCC->APBENR1 |= RCC_APBENR1_I2C1EN;
((length + 1) << I2C_CR2_NBYTES_Pos) |
I2C_CR2_START | I2C1->CR1 = 0;
(i2c_address << I2C_CR2_SADD_Pos)
); 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 (!(hw_gpio_get(GPIO_ID_I2C_SCL) && hw_gpio_get(GPIO_ID_I2C_SDA)));
I2C1->TIMINGR = 0x10901032UL;
I2C1->CR1 |= I2C_CR1_PE;
} }
uint32_t hw_i2c_get_error (void) { 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) {
return (I2C1->ISR & I2C_ISR_NACKF); hw_timeout_start();
}
void hw_i2c_raw (uint8_t i2c_address, uint8_t *tx_data, uint8_t tx_length, uint8_t *rx_data, uint8_t rx_length) { while (I2C1->ISR & I2C_ISR_BUSY) {
while (I2C1->ISR & I2C_ISR_BUSY); if (hw_timeout_occured(I2C_TIMEOUT_US_BUSY)) {
return I2C_ERR_BUSY;
}
}
if (tx_length > 0) { if (tx_length > 0) {
uint32_t tx_timeout = ((tx_length + 1) * I2C_TIMEOUT_US_PER_BYTE);
hw_timeout_start();
I2C1->ICR = I2C_ICR_NACKCF; I2C1->ICR = I2C_ICR_NACKCF;
I2C1->CR2 = ( I2C1->CR2 = (
((rx_length == 0) ? I2C_CR2_AUTOEND : 0) | ((rx_length > 0) ? 0 : I2C_CR2_AUTOEND) |
(tx_length << I2C_CR2_NBYTES_Pos) | (tx_length << I2C_CR2_NBYTES_Pos) |
I2C_CR2_START | 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)); uint8_t left = tx_length;
while (left > 0) {
uint32_t isr = I2C1->ISR;
if (isr & I2C_ISR_TXIS) {
I2C1->TXDR = *tx_data++; I2C1->TXDR = *tx_data++;
left -= 1;
}
if (isr & I2C_ISR_NACKF) {
return I2C_ERR_NACK;
}
if (hw_timeout_occured(tx_timeout)) {
return I2C_ERR_TIMEOUT;
}
}
if (rx_length == 0) {
return I2C_OK;
}
while (!(I2C1->ISR & I2C_ISR_TC)) {
if (hw_timeout_occured(tx_timeout)) {
return I2C_ERR_TIMEOUT;
} }
if (!(I2C1->CR2 & I2C_CR2_AUTOEND)) {
while (!(I2C1->ISR & (I2C_ISR_NACKF | I2C_ISR_TC)));
} }
} }
if (rx_length > 0) { if (rx_length > 0) {
uint32_t rx_timeout = ((rx_length + 1) * I2C_TIMEOUT_US_PER_BYTE);
hw_timeout_start();
I2C1->CR2 = ( I2C1->CR2 = (
I2C_CR2_AUTOEND | I2C_CR2_AUTOEND |
(rx_length << I2C_CR2_NBYTES_Pos) | (rx_length << I2C_CR2_NBYTES_Pos) |
I2C_CR2_START | I2C_CR2_START |
I2C_CR2_RD_WRN | 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)); uint8_t left = rx_length;
while (left > 0) {
uint32_t isr = I2C1->ISR;
if (isr & I2C_ISR_RXNE) {
*rx_data++ = I2C1->RXDR; *rx_data++ = I2C1->RXDR;
left -= 1;
}
if (hw_timeout_occured(rx_timeout)) {
return I2C_ERR_TIMEOUT;
}
} }
} }
if ((tx_length > 0) || (rx_length > 0)) { return I2C_OK;
while (!(I2C1->ISR & I2C_ISR_STOPF));
}
} }
void hw_i2c_disable_irq (void) {
NVIC_DisableIRQ(I2C1_IRQn);
}
void hw_i2c_enable_irq (void) { static void hw_crc32_init (void) {
NVIC_EnableIRQ(I2C1_IRQn); RCC->AHBENR |= RCC_AHBENR_CRCEN;
}
void hw_tim_setup (tim_id_t id, uint16_t delay, void (*callback)(void)) { CRC->CR = (CRC_CR_REV_OUT | CRC_CR_REV_IN_0);
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));
}
} }
void hw_crc32_reset (void) { void hw_crc32_reset (void) {
@ -334,10 +441,15 @@ uint32_t hw_crc32_calculate (uint8_t *data, uint32_t length) {
return (CRC->DR ^ 0xFFFFFFFF); return (CRC->DR ^ 0xFFFFFFFF);
} }
uint32_t hw_flash_size (void) { uint32_t hw_flash_size (void) {
return FLASH_SIZE; return FLASH_SIZE;
} }
hw_flash_t hw_flash_read (uint32_t offset) {
return *(uint64_t *) (FLASH_BASE + offset);
}
static void hw_flash_unlock (void) { static void hw_flash_unlock (void) {
while (FLASH->SR & FLASH_SR_BSY1); while (FLASH->SR & FLASH_SR_BSY1);
if (FLASH->CR & FLASH_CR_LOCK) { if (FLASH->CR & FLASH_CR_LOCK) {
@ -363,13 +475,10 @@ void hw_flash_program (uint32_t offset, hw_flash_t value) {
FLASH->CR &= ~(FLASH_CR_PG); 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) { void hw_reset (loader_parameters_t *parameters) {
if (parameters != NULL) { if (parameters != NULL) {
RCC->APBENR1 |= RCC_APBENR1_PWREN | RCC_APBENR1_RTCAPBEN; RCC->APBENR1 |= (RCC_APBENR1_PWREN | RCC_APBENR1_RTCAPBEN);
PWR->CR1 |= PWR_CR1_DBP; PWR->CR1 |= PWR_CR1_DBP;
TAMP->BKP0R = parameters->magic; TAMP->BKP0R = parameters->magic;
TAMP->BKP1R = parameters->flags; TAMP->BKP1R = parameters->flags;
@ -382,8 +491,9 @@ void hw_reset (loader_parameters_t *parameters) {
NVIC_SystemReset(); NVIC_SystemReset();
} }
void hw_loader_get_parameters (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->magic = TAMP->BKP0R;
parameters->flags = TAMP->BKP1R; parameters->flags = TAMP->BKP1R;
parameters->mcu_address = TAMP->BKP2R; parameters->mcu_address = TAMP->BKP2R;
@ -399,280 +509,104 @@ 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);
} }
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 = ( #define ADC_VREF_CAL_POINT (3000)
((2 - 1) << RCC_PLLCFGR_PLLR_Pos) #define ADC_VREF_CAL_VALUE (*(uint16_t *) (0x1FFF75AAUL))
| RCC_PLLCFGR_PLLREN
| (16 << RCC_PLLCFGR_PLLN_Pos)
| ((2 - 1) << RCC_PLLCFGR_PLLM_Pos)
| RCC_PLLCFGR_PLLSRC_HSI
);
RCC->CR |= RCC_CR_PLLON; #define TEMP_CAL_POINT_1 (30)
while ((RCC->CR & RCC_CR_PLLRDY_Msk) != RCC_CR_PLLRDY); #define TEMP_CAL_VALUE_1 (*(uint16_t *) (0x1FFF75A8UL))
RCC->CFGR = RCC_CFGR_SW_1; #define TEMP_CAL_POINT_2 (130)
while ((RCC->CFGR & RCC_CFGR_SWS_Msk) != RCC_CFGR_SWS_1); #define TEMP_CAL_VALUE_2 (*(uint16_t *) (0x1FFF75CAUL))
RCC->IOPENR |= RCC_IOPENR_GPIOAEN | RCC_IOPENR_GPIOBEN; #define TEMP_CAL_VREF (3000)
SysTick->LOAD = (((64000000 / 1000)) - 1); #define TEMP_SCALE (10)
SysTick->VAL = 0;
SysTick->CTRL = (SysTick_CTRL_CLKSOURCE_Msk | SysTick_CTRL_ENABLE_Msk);
static void hw_adc_init (void) {
RCC->APBENR2 |= RCC_APBENR2_ADCEN;
ADC1->CFGR2 = ADC_CFGR2_CKMODE_1;
ADC->CCR = (ADC_CCR_TSEN | ADC_CCR_VREFEN);
ADC1->CR = ADC_CR_ADVREGEN;
hw_delay_us(120);
ADC1->ISR = ADC_ISR_EOCAL;
ADC1->CR |= ADC_CR_ADCAL;
while (!(ADC1->ISR & ADC_ISR_EOCAL));
ADC1->CFGR1 = (ADC_CFGR1_AUTOFF | ADC_CFGR1_WAIT | ADC_CFGR1_SCANDIR);
ADC1->CFGR2 |= (ADC_CFGR2_OVSS_2 | ADC_CFGR2_OVSR_1 | ADC_CFGR2_OVSR_0 | ADC_CFGR2_OVSE);
ADC1->SMPR = (ADC_SMPR_SMP1_2 | ADC_SMPR_SMP1_1 | ADC_SMPR_SMP1_0);
ADC1->ISR = ADC_ISR_CCRDY;
ADC1->CHSELR = (ADC_CHSELR_CHSEL13 | ADC_CHSELR_CHSEL12);
while (!(ADC1->ISR & ADC_ISR_CCRDY));
ADC1->CR |= ADC_CR_ADEN;
}
void hw_adc_read_voltage_temperature (uint16_t *voltage, int16_t *temperature) {
ADC1->CR |= ADC_CR_ADSTART;
while (!(ADC1->ISR & ADC_ISR_EOC));
uint16_t adc_vref = ((ADC_VREF_CAL_POINT * ADC_VREF_CAL_VALUE) / ADC1->DR);
while (!(ADC1->ISR & ADC_ISR_EOC));
int16_t adc_temp = ((ADC1->DR * adc_vref) / TEMP_CAL_VREF);
*voltage = adc_vref;
*temperature = (
((adc_temp - TEMP_CAL_VALUE_1) * (TEMP_CAL_POINT_2 - TEMP_CAL_POINT_1) * TEMP_SCALE) /
(TEMP_CAL_VALUE_2 - TEMP_CAL_VALUE_1)
) + (TEMP_CAL_POINT_1 * TEMP_SCALE);
}
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); 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); static void hw_misc_init (void) {
DMAMUX1_Channel1->CCR = (17 << DMAMUX_CxCR_DMAREQ_ID_Pos); 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);
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);
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_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_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_PP, 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) { void hw_primer_init (void) {
hw_init_mcu(); hw_clock_init();
hw_init_spi(); hw_timeout_init();
hw_init_i2c(); hw_delay_init();
hw_init_uart(); hw_led_init();
hw_init_tim(); hw_uart_init();
hw_init_crc(); hw_spi_init();
hw_init_misc(); hw_i2c_init();
hw_crc32_init();
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_loader_init (void) { void hw_loader_init (void) {
hw_init_mcu(); hw_clock_init();
hw_init_spi(); hw_timeout_init();
hw_delay_init();
hw_led_init();
hw_spi_init();
} }
void hw_primer_init (void) { void hw_app_init (void) {
hw_init_mcu(); hw_clock_init();
hw_init_spi(); hw_timeout_init();
hw_init_i2c(); hw_delay_init();
hw_init_uart(); hw_adc_init();
hw_init_crc(); hw_led_init();
} hw_misc_init();
hw_uart_init();
hw_spi_init();
void EXTI0_1_IRQHandler (void) { hw_i2c_init();
for (int i = 0; i <= 1; i++) { hw_crc32_init();
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;
}
} }

View File

@ -7,6 +7,7 @@
#define GPIO_PORT_PIN(p, n) ((((p) & 0x07) << 4) | ((n) & 0x0F)) #define GPIO_PORT_PIN(p, n) ((((p) & 0x07) << 4) | ((n) & 0x0F))
typedef enum { typedef enum {
GPIO_ID_N64_RESET = GPIO_PORT_PIN(0, 0), GPIO_ID_N64_RESET = GPIO_PORT_PIN(0, 0),
GPIO_ID_N64_CIC_CLK = GPIO_PORT_PIN(0, 1), GPIO_ID_N64_CIC_CLK = GPIO_PORT_PIN(0, 1),
@ -25,22 +26,11 @@ typedef enum {
} gpio_id_t; } gpio_id_t;
typedef enum { typedef enum {
GPIO_IRQ_FALLING = 0b01, I2C_OK,
GPIO_IRQ_RISING = 0b10, I2C_ERR_BUSY,
} gpio_irq_t; I2C_ERR_TIMEOUT,
I2C_ERR_NACK,
typedef enum { } i2c_err_t;
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;
typedef uint64_t hw_flash_t; typedef uint64_t hw_flash_t;
@ -59,39 +49,48 @@ typedef struct {
} loader_parameters_t; } 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_us (uint32_t delay_us);
void hw_delay_ms (uint32_t delay_ms);
void hw_systick_config (uint32_t period_ms, void (*callback) (void));
uint32_t hw_gpio_get (gpio_id_t id); uint32_t hw_gpio_get (gpio_id_t id);
void hw_gpio_set (gpio_id_t id); void hw_gpio_set (gpio_id_t id);
void hw_gpio_reset (gpio_id_t id); void hw_gpio_reset (gpio_id_t id);
void hw_uart_read (uint8_t *data, int length); void hw_uart_read (uint8_t *data, int length);
void hw_uart_write (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_start (void);
void hw_spi_stop (void); void hw_spi_stop (void);
void hw_spi_trx (uint8_t *data, int length, spi_direction_t direction); void hw_spi_rx (uint8_t *data, int length);
void hw_i2c_read (uint8_t i2c_address, uint8_t address, uint8_t *data, uint8_t length, void (*callback)(void)); void hw_spi_tx (uint8_t *data, int length);
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); 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_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_crc32_reset (void); void hw_crc32_reset (void);
uint32_t hw_crc32_calculate (uint8_t *data, uint32_t length); uint32_t hw_crc32_calculate (uint8_t *data, uint32_t length);
uint32_t hw_flash_size (void); uint32_t hw_flash_size (void);
hw_flash_t hw_flash_read (uint32_t offset);
void hw_flash_erase (void); void hw_flash_erase (void);
void hw_flash_program (uint32_t offset, hw_flash_t value); 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_reset (loader_parameters_t *parameters);
void hw_loader_get_parameters (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_adc_read_voltage_temperature (uint16_t *voltage, int16_t *temperature);
void hw_loader_init (void);
void hw_primer_init (void); void hw_primer_init (void);
void hw_loader_init (void);
void hw_app_init (void);
#endif #endif

View File

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

View File

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

View File

@ -114,27 +114,33 @@ static void lcmxo2_write_data (uint8_t *buffer, uint32_t length) {
static void lcmxo2_reset_bus (void) { static void lcmxo2_reset_bus (void) {
#ifdef LCMXO2_I2C #ifdef LCMXO2_I2C
uint8_t reset_data = 0; 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 #else
lcmxo2_reg_set(LCMXO2_CFGCR, CFGCR_RSTE); lcmxo2_reg_set(LCMXO2_CFGCR, CFGCR_RSTE);
lcmxo2_reg_set(LCMXO2_CFGCR, 0); lcmxo2_reg_set(LCMXO2_CFGCR, 0);
#endif #endif
} }
static void lcmxo2_execute_cmd (uint8_t cmd, uint32_t arg, cmd_type_t type, uint8_t *buffer, uint8_t length, bool write) { static bool lcmxo2_execute_cmd (uint8_t cmd, uint32_t arg, cmd_type_t type, uint8_t *buffer, uint8_t length, bool write) {
#ifdef LCMXO2_I2C #ifdef LCMXO2_I2C
uint8_t packet[20] = { cmd, ((arg >> 16) & 0xFF), ((arg >> 8) & 0xFF), (arg & 0xFF) }; uint8_t packet[20] = { cmd, ((arg >> 16) & 0xFF), ((arg >> 8) & 0xFF), (arg & 0xFF) };
int packet_length = ((type == CMD_TWO_OP) ? 3 : 4); int packet_length = ((type == CMD_TWO_OP) ? 3 : 4);
if (write) { if (write) {
for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) {
packet[packet_length + i] = buffer[i]; packet[packet_length + i] = buffer[i];
} }
packet_length += length; packet_length += length;
} }
hw_i2c_raw(LCMXO2_I2C_ADDR_CFG, packet, packet_length, buffer, (write ? 0 : length));
i2c_err_t err = hw_i2c_trx(LCMXO2_I2C_ADDR_CFG, packet, packet_length, buffer, (write ? 0 : length));
return (err != I2C_OK);
#else #else
uint32_t data = (cmd << 24) | (arg & 0x00FFFFFF);
lcmxo2_reg_set(LCMXO2_CFGCR, CFGCR_WBCE); lcmxo2_reg_set(LCMXO2_CFGCR, CFGCR_WBCE);
uint32_t data = (cmd << 24) | (arg & 0x00FFFFFF);
fpga_reg_set(REG_VENDOR_DATA, data); fpga_reg_set(REG_VENDOR_DATA, data);
fpga_reg_set(REG_VENDOR_SCR, fpga_reg_set(REG_VENDOR_SCR,
(LCMXO2_CFGTXDR << VENDOR_SCR_ADDRESS_BIT) | (LCMXO2_CFGTXDR << VENDOR_SCR_ADDRESS_BIT) |
@ -143,7 +149,9 @@ static void lcmxo2_execute_cmd (uint8_t cmd, uint32_t arg, cmd_type_t type, uint
VENDOR_SCR_WRITE | VENDOR_SCR_WRITE |
VENDOR_SCR_START VENDOR_SCR_START
); );
while (fpga_reg_get(REG_VENDOR_SCR) & VENDOR_SCR_BUSY); while (fpga_reg_get(REG_VENDOR_SCR) & VENDOR_SCR_BUSY);
if (length > 0) { if (length > 0) {
if (write) { if (write) {
lcmxo2_write_data(buffer, length); lcmxo2_write_data(buffer, length);
@ -151,82 +159,105 @@ static void lcmxo2_execute_cmd (uint8_t cmd, uint32_t arg, cmd_type_t type, uint
lcmxo2_read_data(buffer, length); lcmxo2_read_data(buffer, length);
} }
} }
lcmxo2_reg_set(LCMXO2_CFGCR, 0); lcmxo2_reg_set(LCMXO2_CFGCR, 0);
return false;
#endif #endif
} }
static void lcmxo2_read_device_id (uint8_t *id) { static bool lcmxo2_read_device_id (uint8_t *id) {
lcmxo2_execute_cmd(IDCODE_PUB, 0, CMD_NORMAL, id, DEVICE_ID_SIZE, false); return lcmxo2_execute_cmd(IDCODE_PUB, 0, CMD_NORMAL, id, DEVICE_ID_SIZE, false);
} }
static uint32_t lcmxo2_read_status (void) { static uint32_t lcmxo2_read_status (uint32_t *status) {
uint32_t status = 0; uint32_t tmp = 0;
lcmxo2_execute_cmd(LSC_READ_STATUS, 0, CMD_NORMAL, (uint8_t *) (&status), 4, false); bool error = lcmxo2_execute_cmd(LSC_READ_STATUS, 0, CMD_NORMAL, (uint8_t *) (&tmp), 4, false);
return SWAP32(status); *status = SWAP32(tmp);
return error;
} }
static bool lcmxo2_wait_busy (void) { static bool lcmxo2_wait_busy (void) {
bool error;
uint32_t status; uint32_t status;
do { do {
status = lcmxo2_read_status(); error = lcmxo2_read_status(&status);
} while(status & LSC_STATUS_BUSY); } while ((!error) && (status & LSC_STATUS_BUSY));
return (status & LSC_STATUS_FAIL); return (error) || (status & LSC_STATUS_FAIL);
} }
static bool lcmxo2_enable_flash (void) { static bool lcmxo2_enable_flash (void) {
#ifdef LCMXO2_I2C #ifdef LCMXO2_I2C
lcmxo2_execute_cmd(ISC_ENABLE, 0x080000, CMD_TWO_OP, NULL, 0, false); if (lcmxo2_execute_cmd(ISC_ENABLE, 0x080000, CMD_TWO_OP, NULL, 0, false)) {
return true;
}
#else #else
lcmxo2_execute_cmd(ISC_ENABLE_X, 0x080000, CMD_NORMAL, NULL, 0, false); if (lcmxo2_execute_cmd(ISC_ENABLE_X, 0x080000, CMD_NORMAL, NULL, 0, false)) {
return true;
}
#endif #endif
return lcmxo2_wait_busy(); return lcmxo2_wait_busy();
} }
static void lcmxo2_disable_flash (void) { static bool lcmxo2_disable_flash (void) {
lcmxo2_wait_busy(); if (lcmxo2_wait_busy()) {
lcmxo2_execute_cmd(ISC_DISABLE, 0, CMD_TWO_OP, NULL, 0, false); return true;
lcmxo2_execute_cmd(ISC_NOOP, 0xFFFFFF, CMD_NORMAL, NULL, 0, false); }
if (lcmxo2_execute_cmd(ISC_DISABLE, 0, CMD_TWO_OP, NULL, 0, false)) {
return true;
}
return lcmxo2_execute_cmd(ISC_NOOP, 0xFFFFFF, CMD_NORMAL, NULL, 0, false);
} }
static bool lcmxo2_erase_featbits (void) { static bool lcmxo2_erase_featbits (void) {
lcmxo2_execute_cmd(ISC_ERASE, ISC_ERASE_FEATURE, CMD_NORMAL, NULL, 0, false); if (lcmxo2_execute_cmd(ISC_ERASE, ISC_ERASE_FEATURE, CMD_NORMAL, NULL, 0, false)) {
return true;
}
return lcmxo2_wait_busy(); return lcmxo2_wait_busy();
} }
static bool lcmxo2_erase_flash (void) { static bool lcmxo2_erase_flash (void) {
lcmxo2_execute_cmd(ISC_ERASE, (ISC_ERASE_UFM | ISC_ERASE_CFG), CMD_NORMAL, NULL, 0, false); if (lcmxo2_execute_cmd(ISC_ERASE, (ISC_ERASE_UFM | ISC_ERASE_CFG), CMD_NORMAL, NULL, 0, false)) {
return true;
}
return lcmxo2_wait_busy(); return lcmxo2_wait_busy();
} }
static void lcmxo2_reset_flash_address (void) { static bool lcmxo2_reset_flash_address (void) {
lcmxo2_execute_cmd(LSC_INIT_ADDRESS, 0, CMD_NORMAL, NULL, 0, false); return lcmxo2_execute_cmd(LSC_INIT_ADDRESS, 0, CMD_NORMAL, NULL, 0, false);
} }
static bool lcmxo2_write_flash_page (uint8_t *buffer) { static bool lcmxo2_write_flash_page (uint8_t *buffer) {
lcmxo2_execute_cmd(LSC_PROG_INCR_NV, 1, CMD_NORMAL, buffer, FLASH_PAGE_SIZE, true); if (lcmxo2_execute_cmd(LSC_PROG_INCR_NV, 1, CMD_NORMAL, buffer, FLASH_PAGE_SIZE, true)) {
return true;
}
return lcmxo2_wait_busy(); return lcmxo2_wait_busy();
} }
static void lcmxo2_read_flash_page (uint8_t *buffer) { static bool lcmxo2_read_flash_page (uint8_t *buffer) {
lcmxo2_execute_cmd(LSC_READ_INCR_NV, 1, CMD_DELAYED, buffer, FLASH_PAGE_SIZE, false); return lcmxo2_execute_cmd(LSC_READ_INCR_NV, 1, CMD_DELAYED, buffer, FLASH_PAGE_SIZE, false);
} }
static bool lcmxo2_program_done (void) { static bool lcmxo2_program_done (void) {
lcmxo2_execute_cmd(ISC_PROGRAM_DONE, 0, CMD_NORMAL, NULL, 0, false); if (lcmxo2_execute_cmd(ISC_PROGRAM_DONE, 0, CMD_NORMAL, NULL, 0, false)) {
return true;
}
return lcmxo2_wait_busy(); return lcmxo2_wait_busy();
} }
static bool lcmxo2_write_featbits (uint8_t *buffer) { static bool lcmxo2_write_featbits (uint8_t *buffer) {
lcmxo2_execute_cmd(LSC_PROG_FEABITS, 0, CMD_NORMAL, buffer, FEATBITS_SIZE, true); if (lcmxo2_execute_cmd(LSC_PROG_FEABITS, 0, CMD_NORMAL, buffer, FEATBITS_SIZE, true)) {
return true;
}
return lcmxo2_wait_busy(); return lcmxo2_wait_busy();
} }
static void lcmxo2_read_featbits (uint8_t *buffer) { static bool lcmxo2_read_featbits (uint8_t *buffer) {
lcmxo2_execute_cmd(LSC_READ_FEABITS, 0, CMD_NORMAL, buffer, FEATBITS_SIZE, false); return lcmxo2_execute_cmd(LSC_READ_FEABITS, 0, CMD_NORMAL, buffer, FEATBITS_SIZE, false);
} }
static void lcmxo2_refresh (void) { static bool lcmxo2_refresh (void) {
lcmxo2_execute_cmd(LSC_REFRESH, 0, CMD_TWO_OP, NULL, 0, false); return lcmxo2_execute_cmd(LSC_REFRESH, 0, CMD_TWO_OP, NULL, 0, false);
} }
static vendor_error_t lcmxo2_fail (vendor_error_t error) { static vendor_error_t lcmxo2_fail (vendor_error_t error) {
@ -346,20 +377,29 @@ static bool primer_check_rx_length (primer_cmd_e cmd, size_t rx_length) {
static bool lcmxo2_init_featbits (void) { static bool lcmxo2_init_featbits (void) {
uint8_t programmed[2] = { 0x00, 0x00 }; uint8_t programmed[2] = { 0x00, 0x00 };
uint8_t target[2] = { FEATBITS_0_SPI_OFF, FEATBITS_1_PROGRAMN_OFF }; uint8_t target[2] = { FEATBITS_0_SPI_OFF, FEATBITS_1_PROGRAMN_OFF };
lcmxo2_read_featbits(programmed);
if (lcmxo2_read_featbits(programmed)) {
return true;
}
if ((programmed[0] == target[0]) && (programmed[1] == target[1])) { if ((programmed[0] == target[0]) && (programmed[1] == target[1])) {
return false; return false;
} }
if (lcmxo2_erase_featbits()) { if (lcmxo2_erase_featbits()) {
return true; return true;
} }
if (lcmxo2_write_featbits(target)) { if (lcmxo2_write_featbits(target)) {
return true; return true;
} }
lcmxo2_read_featbits(programmed); if (lcmxo2_read_featbits(programmed)) {
return true;
}
if ((programmed[0] != target[0]) || (programmed[1] != target[1])) { if ((programmed[0] != target[0]) || (programmed[1] != target[1])) {
return true; return true;
} }
return false; return false;
} }
@ -403,7 +443,7 @@ void vendor_initial_configuration (vendor_get_cmd_t get_cmd, vendor_send_respons
break; break;
case CMD_GET_DEVICE_ID: case CMD_GET_DEVICE_ID:
lcmxo2_read_device_id(buffer); error = lcmxo2_read_device_id(buffer);
tx_length = 4; tx_length = 4;
break; break;
@ -416,7 +456,7 @@ void vendor_initial_configuration (vendor_get_cmd_t get_cmd, vendor_send_respons
break; break;
case CMD_RESET_ADDRESS: case CMD_RESET_ADDRESS:
lcmxo2_reset_flash_address(); error = lcmxo2_reset_flash_address();
break; break;
case CMD_WRITE_PAGE: case CMD_WRITE_PAGE:
@ -424,7 +464,7 @@ void vendor_initial_configuration (vendor_get_cmd_t get_cmd, vendor_send_respons
break; break;
case CMD_READ_PAGE: case CMD_READ_PAGE:
lcmxo2_read_flash_page(buffer); error = lcmxo2_read_flash_page(buffer);
tx_length = FLASH_PAGE_SIZE; tx_length = FLASH_PAGE_SIZE;
break; break;
@ -437,7 +477,7 @@ void vendor_initial_configuration (vendor_get_cmd_t get_cmd, vendor_send_respons
break; break;
case CMD_REFRESH: case CMD_REFRESH:
lcmxo2_refresh(); error = lcmxo2_refresh();
hw_delay_ms(200); hw_delay_ms(200);
break; break;

View File

@ -2,102 +2,46 @@
#include "hw.h" #include "hw.h"
#include "led.h" #include "led.h"
#include "rtc.h" #include "rtc.h"
#include "task.h"
#include "timer.h" #include "timer.h"
#define LED_MS_PER_TICK (10) #define LED_REFRESH_PERIOD_MS (50)
#define LED_ERROR_TICKS_PERIOD (50)
#define LED_ERROR_TICKS_ON (25) #define LED_PULSE_LENGTH_MS (200)
#define LED_ACT_TICKS_PERIOD (15)
#define LED_ACT_TICKS_ON (6) #define ERROR_BLINK_PERIOD_MS (100)
#define ERROR_TOTAL_PERIOD_MS (1000)
#define CIC_ERROR_BLINKS (1)
#define RTC_ERROR_BLINKS (2)
static bool error_mode = false; static bool activity_pulse = false;
static uint32_t error_timer = 0; static int activity_pulse_timer = 0;
static volatile bool cic_error = false;
static volatile bool rtc_error = false;
static uint32_t act_timer = 0; static bool cic_error = false;
static uint32_t current_act_counter = 0; static bool rtc_error = false;
static volatile uint32_t next_act_counter = 0; static bool error_active = false;
static int error_timer = 0;
static void led_task_resume (void) { void led_activity_on (void) {
task_set_ready(TASK_ID_LED);
}
static void led_set_state (bool state, bool force) {
rtc_settings_t *settings = rtc_get_settings(); rtc_settings_t *settings = rtc_get_settings();
if (settings->led_enabled || force) { if (!activity_pulse && !error_active && settings->led_enabled) {
if (state) {
hw_gpio_set(GPIO_ID_LED); hw_gpio_set(GPIO_ID_LED);
} else {
hw_gpio_reset(GPIO_ID_LED);
} }
} else { }
void led_activity_off (void) {
rtc_settings_t *settings = rtc_get_settings();
if (!activity_pulse && !error_active && settings->led_enabled) {
hw_gpio_reset(GPIO_ID_LED); hw_gpio_reset(GPIO_ID_LED);
} }
} }
static void led_update_error_mode (void) { void led_activity_pulse (void) {
if (error_mode) { activity_pulse = true;
if (!(cic_error || rtc_error)) { activity_pulse_timer = LED_PULSE_LENGTH_MS;
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;
}
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;
}
}
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);
}
}
} }
@ -106,10 +50,16 @@ void led_blink_error (led_error_t error) {
case LED_ERROR_CIC: case LED_ERROR_CIC:
cic_error = true; cic_error = true;
break; break;
case LED_ERROR_RTC: case LED_ERROR_RTC:
rtc_error = true; rtc_error = true;
break; break;
} }
error_active = (
cic_error |
rtc_error
);
} }
void led_clear_error (led_error_t error) { void led_clear_error (led_error_t error) {
@ -117,32 +67,81 @@ void led_clear_error (led_error_t error) {
case LED_ERROR_CIC: case LED_ERROR_CIC:
cic_error = false; cic_error = false;
break; break;
case LED_ERROR_RTC: case LED_ERROR_RTC:
rtc_error = false; rtc_error = false;
break; break;
} }
error_active = (
cic_error |
rtc_error
);
if (!error_active) {
activity_pulse = false;
activity_pulse_timer = 0;
error_timer = 0;
}
} }
void led_blink_act (void) {
next_act_counter += 1; void led_init (void) {
timer_countdown_start(TIMER_ID_LED, LED_REFRESH_PERIOD_MS);
} }
void led_task (void) {
timer_init();
while (1) { void led_process (void) {
hw_tim_setup(TIM_ID_LED, LED_MS_PER_TICK, led_task_resume); if (!timer_countdown_elapsed(TIMER_ID_LED)) {
return;
}
led_update_error_mode(); timer_countdown_start(TIMER_ID_LED, LED_REFRESH_PERIOD_MS);
if (error_mode) { if (error_active) {
led_process_errors(); int blinks = 0;
if (cic_error) {
blinks = CIC_ERROR_BLINKS;
} else if (rtc_error) {
blinks = RTC_ERROR_BLINKS;
}
bool led_on = false;
for (int i = 0; i < blinks; i++) {
bool lower_bound = (error_timer >= (ERROR_BLINK_PERIOD_MS * (i * 2)));
bool upper_bound = (error_timer < (ERROR_BLINK_PERIOD_MS * ((i * 2) + 1)));
if (lower_bound && upper_bound) {
led_on = true;
break;
}
}
if (led_on) {
hw_gpio_set(GPIO_ID_LED);
} else { } else {
led_process_act(); hw_gpio_reset(GPIO_ID_LED);
} }
timer_update(); error_timer += LED_REFRESH_PERIOD_MS;
task_yield(); if (error_timer >= ERROR_TOTAL_PERIOD_MS) {
error_timer = 0;
}
return;
}
if (activity_pulse) {
if (activity_pulse_timer > 0) {
hw_gpio_set(GPIO_ID_LED);
} else {
activity_pulse = false;
hw_gpio_reset(GPIO_ID_LED);
return;
}
activity_pulse_timer -= LED_REFRESH_PERIOD_MS;
} }
} }

View File

@ -8,10 +8,16 @@ typedef enum {
} led_error_t; } led_error_t;
void led_activity_on (void);
void led_activity_off (void);
void led_activity_pulse (void);
void led_blink_error (led_error_t error); void led_blink_error (led_error_t error);
void led_clear_error (led_error_t error); void led_clear_error (led_error_t error);
void led_blink_act (void);
void led_task (void); void led_init (void);
void led_process (void);
#endif #endif

View File

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

View File

@ -19,7 +19,7 @@ static uint8_t primer_get_command (uint8_t *buffer, uint8_t *rx_length) {
uint32_t received_crc32; uint32_t received_crc32;
uint8_t token[4]; uint8_t token[4];
while (1) { while (true) {
hw_crc32_reset(); hw_crc32_reset();
primer_get_and_calculate_crc32(token, 4, &calculated_crc32); primer_get_and_calculate_crc32(token, 4, &calculated_crc32);
@ -69,7 +69,10 @@ static void primer_send_response (uint8_t cmd, uint8_t *buffer, uint8_t tx_lengt
void primer (void) { void primer (void) {
hw_primer_init(); hw_primer_init();
vendor_initial_configuration(primer_get_command, primer_send_response); vendor_initial_configuration(primer_get_command, primer_send_response);
hw_uart_wait_busy();
hw_uart_write_wait_busy();
hw_reset(NULL); hw_reset(NULL);
} }

View File

@ -2,7 +2,7 @@
#include "hw.h" #include "hw.h"
#include "led.h" #include "led.h"
#include "rtc.h" #include "rtc.h"
#include "task.h" #include "timer.h"
#define RTC_I2C_ADDRESS (0xDE) #define RTC_I2C_ADDRESS (0xDE)
@ -28,27 +28,27 @@
#define RTC_SETTINGS_VERSION (1) #define RTC_SETTINGS_VERSION (1)
#define RTC_TIME_REFRESH_PERIOD_MS (500)
static rtc_time_t rtc_time = { static rtc_time_t rtc_time = {
.second = 0x00, .second = 0x00,
.minute = 0x00, .minute = 0x00,
.hour = 0x12, .hour = 0x12,
.weekday = 0x02, .weekday = 0x01,
.day = 0x01, .day = 0x01,
.month = 0x03, .month = 0x01,
.year = 0x22 .year = 0x24
}; };
static bool rtc_time_valid = false; static bool rtc_time_pending = false;
static volatile bool rtc_time_pending = false;
static uint8_t rtc_region = 0xFF; 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 = { static rtc_settings_t rtc_settings = {
.led_enabled = true, .led_enabled = true,
}; };
static volatile bool rtc_settings_pending = false; static bool rtc_settings_pending = false;
static volatile bool rtc_initialized = false;
static const uint8_t rtc_regs_bit_mask[7] = { static const uint8_t rtc_regs_bit_mask[7] = {
0b01111111, 0b01111111,
@ -61,30 +61,29 @@ static const uint8_t rtc_regs_bit_mask[7] = {
}; };
static void rtc_task_resume (void) { static bool rtc_read (uint8_t address, uint8_t *data, uint8_t length) {
task_set_ready(TASK_ID_RTC); if (hw_i2c_trx(RTC_I2C_ADDRESS, &address, 1, data, length) != I2C_OK) {
}
static void rtc_on_error (void) {
rtc_time_valid = false;
led_blink_error(LED_ERROR_RTC); led_blink_error(LED_ERROR_RTC);
task_yield(); return true;
}
return false;
} }
static void rtc_read (uint8_t address, uint8_t *data, uint8_t length) { static bool rtc_write (uint8_t address, uint8_t *data, uint8_t length) {
hw_i2c_read(RTC_I2C_ADDRESS, address, data, length, rtc_task_resume); uint8_t buffer[16];
task_yield(); buffer[0] = address;
if (hw_i2c_get_error()) {
rtc_on_error();
}
}
static void rtc_write (uint8_t address, uint8_t *data, uint8_t length) { for (int i = 0; i < length; i++) {
hw_i2c_write(RTC_I2C_ADDRESS, address, data, length, rtc_task_resume); buffer[i + 1] = data[i];
task_yield();
if (hw_i2c_get_error()) {
rtc_on_error();
} }
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) { static void rtc_sanitize_time (uint8_t *regs) {
@ -98,19 +97,18 @@ static void rtc_osc_stop (void) {
rtc_write(RTC_ADDRESS_RTCSEC, &tmp, 1); rtc_write(RTC_ADDRESS_RTCSEC, &tmp, 1);
do { while ((!rtc_read(RTC_ADDRESS_RTCWKDAY, &tmp, 1)) && (tmp & RTC_RTCWKDAY_OSCRUN));
rtc_read(RTC_ADDRESS_RTCWKDAY, &tmp, 1);
} while (tmp & RTC_RTCWKDAY_OSCRUN);
} }
static void rtc_read_time (void) { static void rtc_read_time (void) {
uint8_t regs[7]; uint8_t regs[7];
rtc_read(RTC_ADDRESS_RTCSEC, regs, 7); if (rtc_read(RTC_ADDRESS_RTCSEC, regs, 7)) {
return;
}
rtc_sanitize_time(regs); rtc_sanitize_time(regs);
if (!rtc_time_pending) {
rtc_time.second = regs[0]; rtc_time.second = regs[0];
rtc_time.minute = regs[1]; rtc_time.minute = regs[1];
rtc_time.hour = regs[2]; rtc_time.hour = regs[2];
@ -118,9 +116,6 @@ static void rtc_read_time (void) {
rtc_time.day = regs[4]; rtc_time.day = regs[4];
rtc_time.month = regs[5]; rtc_time.month = regs[5];
rtc_time.year = regs[6]; rtc_time.year = regs[6];
rtc_time_valid = true;
}
} }
static void rtc_write_time (void) { static void rtc_write_time (void) {
@ -161,12 +156,58 @@ static void rtc_write_settings (void) {
rtc_write(RTC_ADDRESS_SRAM_SETTINGS, (uint8_t *) (&rtc_settings), sizeof(rtc_settings)); 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; bool uninitialized = false;
const char *magic = "SC64"; const char *magic = "SC64";
uint8_t buffer[4]; uint8_t buffer[4];
uint32_t settings_version; uint32_t settings_version;
for (int i = 0; i < 4; i++) {
buffer[i] = 0;
}
rtc_read(RTC_ADDRESS_SRAM_MAGIC, buffer, 4); rtc_read(RTC_ADDRESS_SRAM_MAGIC, buffer, 4);
for (int i = 0; i < 4; i++) { for (int i = 0; i < 4; i++) {
@ -179,7 +220,6 @@ static void rtc_init (void) {
if (uninitialized) { if (uninitialized) {
buffer[0] = 0; buffer[0] = 0;
rtc_write(RTC_ADDRESS_SRAM_MAGIC, (uint8_t *) (magic), 4); 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(RTC_ADDRESS_OSCTRIM, buffer, 1);
rtc_write_time(); rtc_write_time();
rtc_write_region(); rtc_write_region();
@ -192,82 +232,38 @@ static void rtc_init (void) {
rtc_write(RTC_ADDRESS_SRAM_VERSION, (uint8_t *) (&settings_version), 4); rtc_write(RTC_ADDRESS_SRAM_VERSION, (uint8_t *) (&settings_version), 4);
rtc_write_settings(); 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_region();
rtc_read_settings(); rtc_read_settings();
rtc_initialized = true; timer_countdown_start(TIMER_ID_RTC, RTC_TIME_REFRESH_PERIOD_MS);
}
void rtc_process (void) {
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);
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);
}
while (1) {
if (rtc_time_pending) { if (rtc_time_pending) {
rtc_time_pending = false; rtc_time_pending = false;
rtc_write_time(); rtc_write_time();
@ -283,52 +279,26 @@ void rtc_task (void) {
rtc_write_settings(); rtc_write_settings();
} }
if (timer_countdown_elapsed(TIMER_ID_RTC)) {
timer_countdown_start(TIMER_ID_RTC, RTC_TIME_REFRESH_PERIOD_MS);
rtc_read_time(); rtc_read_time();
hw_tim_setup(TIM_ID_RTC, 50, rtc_task_resume);
task_yield();
}
}
void rtc_process (void) {
rtc_time_t time;
uint32_t data[2]; 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)) {
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);
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);
data[0] = ( data[0] = (
((time.weekday - 1) << 24) | ((rtc_time.weekday - 1) << 24) |
(time.hour << 16) | (rtc_time.hour << 16) |
(time.minute << 8) | (rtc_time.minute << 8) |
(time.second << 0) (rtc_time.second << 0)
); );
data[1] = ( data[1] = (
(time.year << 16) | (rtc_time.year << 16) |
(time.month << 8) | (rtc_time.month << 8) |
(time.day << 0) (rtc_time.day << 0)
); );
fpga_reg_set(REG_RTC_TIME_0, data[0]); fpga_reg_set(REG_RTC_TIME_0, data[0]);
fpga_reg_set(REG_RTC_TIME_1, data[1]); fpga_reg_set(REG_RTC_TIME_1, data[1]);
}
} }

View File

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

View File

@ -1,9 +1,7 @@
#include <stdbool.h>
#include <stdint.h>
#include "fpga.h" #include "fpga.h"
#include "hw.h" #include "hw.h"
#include "led.h"
#include "sd.h" #include "sd.h"
#include "timer.h"
#define SD_INIT_BUFFER_ADDRESS (0x05002800UL) #define SD_INIT_BUFFER_ADDRESS (0x05002800UL)
@ -33,6 +31,8 @@
#define SWITCH_FUNCTION_GROUP_1 (SD_INIT_BUFFER_ADDRESS + 12) #define SWITCH_FUNCTION_GROUP_1 (SD_INIT_BUFFER_ADDRESS + 12)
#define SWITCH_FUNCTION_GROUP_1_HS (1 << 1) #define SWITCH_FUNCTION_GROUP_1_HS (1 << 1)
#define TIMEOUT_INIT_MS (1000)
#define DAT_BLOCK_MAX_COUNT (256) #define DAT_BLOCK_MAX_COUNT (256)
#define DAT_TIMEOUT_INIT_MS (2000) #define DAT_TIMEOUT_INIT_MS (2000)
#define DAT_TIMEOUT_DATA_MS (5000) #define DAT_TIMEOUT_DATA_MS (5000)
@ -60,6 +60,12 @@ typedef enum {
DAT_WRITE, DAT_WRITE,
} dat_mode_t; } dat_mode_t;
typedef enum {
DAT_OK,
DAT_ERR_IO,
DAT_ERR_TIMEOUT,
} dat_err_t;
struct process { struct process {
bool card_initialized; bool card_initialized;
@ -67,7 +73,6 @@ struct process {
uint32_t rca; uint32_t rca;
uint8_t csd[16]; uint8_t csd[16];
uint8_t cid[16]; uint8_t cid[16];
volatile bool timeout;
bool byte_swap; bool byte_swap;
}; };
@ -75,24 +80,6 @@ struct process {
static struct process p; 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) { static void sd_set_clock (sd_clock_t mode) {
fpga_reg_set(REG_SD_SCR, SD_SCR_CLOCK_MODE_OFF); fpga_reg_set(REG_SD_SCR, SD_SCR_CLOCK_MODE_OFF);
@ -198,22 +185,24 @@ static void sd_dat_abort (void) {
fpga_reg_set(REG_SD_DAT, SD_DAT_STOP | SD_DAT_FIFO_FLUSH); fpga_reg_set(REG_SD_DAT, SD_DAT_STOP | SD_DAT_FIFO_FLUSH);
} }
static bool sd_dat_wait (uint16_t timeout) { static dat_err_t sd_dat_wait (uint16_t timeout_ms) {
sd_prepare_timeout(timeout); timer_countdown_start(TIMER_ID_SD, timeout_ms);
do { do {
uint32_t sd_dat = fpga_reg_get(REG_SD_DAT); uint32_t sd_dat = fpga_reg_get(REG_SD_DAT);
uint32_t sd_dma_scr = fpga_reg_get(REG_SD_DMA_SCR); 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))) { if ((!(sd_dat & SD_DAT_BUSY)) && (!(sd_dma_scr & DMA_SCR_BUSY))) {
sd_clear_timeout(); if (sd_dat & SD_DAT_ERROR) {
return (sd_dat & SD_DAT_ERROR); sd_dat_abort();
return DAT_ERR_IO;
} }
} while (!sd_did_timeout()); return DAT_OK;
}
} while (!timer_countdown_elapsed(TIMER_ID_SD));
sd_dat_abort(); sd_dat_abort();
return true; return DAT_ERR_TIMEOUT;
} }
@ -231,8 +220,6 @@ bool sd_card_init (void) {
p.card_initialized = true; p.card_initialized = true;
p.rca = 0; p.rca = 0;
led_blink_act();
sd_set_clock(CLOCK_400KHZ); sd_set_clock(CLOCK_400KHZ);
sd_cmd(0, 0, RSP_NONE, NULL); sd_cmd(0, 0, RSP_NONE, NULL);
@ -248,9 +235,9 @@ bool sd_card_init (void) {
arg = (ACMD41_ARG_HCS | ACMD41_ARG_OCR); arg = (ACMD41_ARG_HCS | ACMD41_ARG_OCR);
} }
sd_prepare_timeout(1000); timer_countdown_start(TIMER_ID_SD, TIMEOUT_INIT_MS);
do { do {
if (sd_did_timeout()) { if (timer_countdown_elapsed(TIMER_ID_SD)) {
sd_card_deinit(); sd_card_deinit();
return true; return true;
} }
@ -266,8 +253,7 @@ bool sd_card_init (void) {
p.card_type_block = (rsp & R3_CCS); p.card_type_block = (rsp & R3_CCS);
break; break;
} }
} while (1); } while (true);
sd_clear_timeout();
if (sd_cmd(2, 0, RSP_R2, NULL)) { if (sd_cmd(2, 0, RSP_R2, NULL)) {
sd_card_deinit(); sd_card_deinit();
@ -308,8 +294,7 @@ bool sd_card_init (void) {
sd_card_deinit(); sd_card_deinit();
return true; return true;
} }
sd_dat_wait(DAT_TIMEOUT_INIT_MS); if (sd_dat_wait(DAT_TIMEOUT_INIT_MS) == DAT_ERR_TIMEOUT) {
if (sd_did_timeout()) {
sd_card_deinit(); sd_card_deinit();
return true; return true;
} }
@ -326,8 +311,7 @@ bool sd_card_init (void) {
sd_card_deinit(); sd_card_deinit();
return true; return true;
} }
sd_dat_wait(DAT_TIMEOUT_INIT_MS); if (sd_dat_wait(DAT_TIMEOUT_INIT_MS) == DAT_ERR_TIMEOUT) {
if (sd_did_timeout()) {
sd_card_deinit(); sd_card_deinit();
return true; return true;
} }
@ -389,6 +373,7 @@ bool sd_set_byte_swap (bool enabled) {
return false; return false;
} }
bool sd_write_sectors (uint32_t address, uint32_t sector, uint32_t count) { bool sd_write_sectors (uint32_t address, uint32_t sector, uint32_t count) {
if (!p.card_initialized || (count == 0)) { if (!p.card_initialized || (count == 0)) {
return true; return true;
@ -400,13 +385,11 @@ bool sd_write_sectors (uint32_t address, uint32_t sector, uint32_t count) {
while (count > 0) { while (count > 0) {
uint32_t blocks = ((count > DAT_BLOCK_MAX_COUNT) ? DAT_BLOCK_MAX_COUNT : count); uint32_t blocks = ((count > DAT_BLOCK_MAX_COUNT) ? DAT_BLOCK_MAX_COUNT : count);
led_blink_act();
if (sd_cmd(25, sector, RSP_R1, NULL)) { if (sd_cmd(25, sector, RSP_R1, NULL)) {
return true; return true;
} }
sd_dat_prepare(address, blocks, DAT_WRITE); sd_dat_prepare(address, blocks, DAT_WRITE);
if (sd_dat_wait(DAT_TIMEOUT_DATA_MS)) { if (sd_dat_wait(DAT_TIMEOUT_DATA_MS) != DAT_OK) {
sd_dat_abort();
sd_cmd(12, 0, RSP_R1b, NULL); sd_cmd(12, 0, RSP_R1b, NULL);
return true; return true;
} }
@ -434,16 +417,13 @@ bool sd_read_sectors (uint32_t address, uint32_t sector, uint32_t count) {
while (count > 0) { while (count > 0) {
uint32_t blocks = ((count > DAT_BLOCK_MAX_COUNT) ? DAT_BLOCK_MAX_COUNT : count); uint32_t blocks = ((count > DAT_BLOCK_MAX_COUNT) ? DAT_BLOCK_MAX_COUNT : count);
led_blink_act();
sd_dat_prepare(address, blocks, DAT_READ); sd_dat_prepare(address, blocks, DAT_READ);
if (sd_cmd(18, sector, RSP_R1, NULL)) { if (sd_cmd(18, sector, RSP_R1, NULL)) {
sd_dat_abort(); sd_dat_abort();
return true; return true;
} }
if (sd_dat_wait(DAT_TIMEOUT_DATA_MS)) { if (sd_dat_wait(DAT_TIMEOUT_DATA_MS) != DAT_OK) {
if (sd_did_timeout()) {
sd_cmd(12, 0, RSP_R1b, NULL); sd_cmd(12, 0, RSP_R1b, NULL);
}
return true; return true;
} }
sd_cmd(12, 0, RSP_R1b, NULL); sd_cmd(12, 0, RSP_R1b, NULL);
@ -455,6 +435,7 @@ bool sd_read_sectors (uint32_t address, uint32_t sector, uint32_t count) {
return false; return false;
} }
bool sd_optimize_sectors (uint32_t address, uint32_t *sector_table, uint32_t count, sd_process_sectors_t sd_process_sectors) { 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 starting_sector = 0;
uint32_t sectors_to_process = 0; uint32_t sectors_to_process = 0;
@ -483,12 +464,14 @@ bool sd_optimize_sectors (uint32_t address, uint32_t *sector_table, uint32_t cou
return false; return false;
} }
void sd_init (void) { void sd_init (void) {
p.card_initialized = false; p.card_initialized = false;
p.byte_swap = false; p.byte_swap = false;
sd_set_clock(CLOCK_STOP); sd_set_clock(CLOCK_STOP);
} }
void sd_process (void) { void sd_process (void) {
if (p.card_initialized && !sd_card_is_inserted()) { if (p.card_initialized && !sd_card_is_inserted()) {
sd_card_deinit(); sd_card_deinit();

View File

@ -3,6 +3,7 @@
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h>
#define SD_SECTOR_SIZE (512) #define SD_SECTOR_SIZE (512)
@ -18,10 +19,14 @@ bool sd_card_is_inserted (void);
uint32_t sd_card_get_status (void); uint32_t sd_card_get_status (void);
bool sd_card_get_info (uint32_t address); bool sd_card_get_info (uint32_t address);
bool sd_set_byte_swap (bool enabled); bool sd_set_byte_swap (bool enabled);
bool sd_write_sectors (uint32_t address, uint32_t sector, uint32_t count); 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_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); 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_init (void);
void sd_process (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" #include "timer.h"
static volatile uint32_t timer[__TIMER_ID_COUNT]; #define TIMER_PERIOD_MS (25)
uint32_t timer_get (timer_id_t id) { typedef struct {
return (uint32_t) (timer[id]); volatile bool pending;
volatile bool running;
volatile uint32_t value;
} timer_t;
static timer_t timer[__TIMER_ID_COUNT];
static void timer_update (void) {
for (timer_id_t id = 0; id < __TIMER_ID_COUNT; id++) {
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_set (timer_id_t id, uint32_t ticks) {
hw_tim_disable_irq(TIM_ID_LED); void timer_countdown_start (timer_id_t id, uint32_t value_ms) {
timer[id] = ticks; hw_enter_critical();
hw_tim_enable_irq(TIM_ID_LED); 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) { void timer_init (void) {
for (timer_id_t id = 0; id < __TIMER_ID_COUNT; id++) { hw_systick_config(TIMER_PERIOD_MS, timer_update);
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;
}
}
} }

View File

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

View File

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

View File

@ -1,9 +1,9 @@
#include "app.h"
#include "cfg.h" #include "cfg.h"
#include "cic.h" #include "cic.h"
#include "dd.h" #include "dd.h"
#include "flash.h" #include "flash.h"
#include "fpga.h" #include "fpga.h"
#include "hw.h"
#include "rtc.h" #include "rtc.h"
#include "timer.h" #include "timer.h"
#include "update.h" #include "update.h"
@ -20,7 +20,10 @@
#define RX_FLUSH_ADDRESS (0x07F00000UL) #define RX_FLUSH_ADDRESS (0x07F00000UL)
#define RX_FLUSH_LENGTH (1 * 1024 * 1024) #define RX_FLUSH_LENGTH (1 * 1024 * 1024)
#define DEBUG_WRITE_TIMEOUT_TICKS (100) #define DEBUG_WRITE_TIMEOUT_MS (1000)
#define DIAGNOSTIC_DATA_MARKER (1 << 31)
#define DIAGNOSTIC_DATA_VERSION (1)
enum rx_state { enum rx_state {
@ -175,7 +178,7 @@ static void usb_rx_process (void) {
p.response_info.dma_length = 0; p.response_info.dma_length = 0;
p.response_info.done_callback = NULL; p.response_info.done_callback = NULL;
if (p.rx_cmd == 'U') { 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 +314,9 @@ static void usb_rx_process (void) {
p.read_length -= length; p.read_length -= length;
p.read_address += length; p.read_address += length;
p.read_ready = true; 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.rx_state = RX_STATE_FLUSH;
p.flush_packet = true; p.flush_packet = true;
} }
@ -382,12 +385,19 @@ static void usb_rx_process (void) {
p.response_info.data[1] = fpga_reg_get(REG_DEBUG_1); p.response_info.data[1] = fpga_reg_get(REG_DEBUG_1);
break; break;
case '%': case '%': {
uint16_t voltage;
int16_t temperature;
hw_adc_read_voltage_temperature(&voltage, &temperature);
p.rx_state = RX_STATE_IDLE; p.rx_state = RX_STATE_IDLE;
p.response_pending = true; p.response_pending = true;
p.response_info.data_length = 16; p.response_info.data_length = 16;
app_get_stack_usage(p.response_info.data); p.response_info.data[0] = (DIAGNOSTIC_DATA_MARKER | DIAGNOSTIC_DATA_VERSION);
p.response_info.data[1] = (uint32_t) (voltage);
p.response_info.data[2] = (uint32_t) (temperature);
p.response_info.data[3] = 0;
break; break;
}
default: default:
p.rx_state = RX_STATE_IDLE; p.rx_state = RX_STATE_IDLE;
@ -521,6 +531,7 @@ bool usb_enqueue_packet (usb_tx_info_t *info) {
return true; return true;
} }
bool usb_prepare_read (uint32_t *args) { bool usb_prepare_read (uint32_t *args) {
if (!p.read_ready) { if (!p.read_ready) {
return false; return false;
@ -543,6 +554,7 @@ void usb_get_read_info (uint32_t *args) {
args[0] |= (scr & USB_SCR_PWRSAV) ? (1 << 29) : 0; args[0] |= (scr & USB_SCR_PWRSAV) ? (1 << 29) : 0;
} }
void usb_init (void) { void usb_init (void) {
fpga_reg_set(REG_USB_DMA_SCR, DMA_SCR_STOP); fpga_reg_set(REG_USB_DMA_SCR, DMA_SCR_STOP);
fpga_reg_set(REG_USB_SCR, USB_SCR_FIFO_FLUSH); fpga_reg_set(REG_USB_SCR, USB_SCR_FIFO_FLUSH);
@ -563,6 +575,7 @@ void usb_init (void) {
usb_rx_cmd_counter = 0; usb_rx_cmd_counter = 0;
} }
void usb_process (void) { void usb_process (void) {
uint32_t scr = fpga_reg_get(REG_USB_SCR); uint32_t scr = fpga_reg_get(REG_USB_SCR);
if (scr & (USB_SCR_PWRSAV | USB_SCR_RESET_STATE | USB_SCR_RESET_PENDING)) { if (scr & (USB_SCR_PWRSAV | USB_SCR_RESET_STATE | USB_SCR_RESET_PENDING)) {

View File

@ -29,9 +29,12 @@ typedef struct usb_tx_info {
void usb_create_packet (usb_tx_info_t *info, usb_packet_cmd_e cmd); 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_enqueue_packet (usb_tx_info_t *info);
bool usb_prepare_read (uint32_t *args); bool usb_prepare_read (uint32_t *args);
void usb_get_read_info (uint32_t *args); void usb_get_read_info (uint32_t *args);
void usb_init (void); void usb_init (void);
void usb_process (void); void usb_process (void);

View File

@ -1,5 +1,6 @@
#include "cfg.h" #include "cfg.h"
#include "fpga.h" #include "fpga.h"
#include "led.h"
#include "sd.h" #include "sd.h"
#include "timer.h" #include "timer.h"
#include "usb.h" #include "usb.h"
@ -7,15 +8,18 @@
#define SAVE_MAX_SECTOR_COUNT (256) #define SAVE_MAX_SECTOR_COUNT (256)
#define EEPROM_ADDRESS (0x05002000) #define EEPROM_ADDRESS (0x05002000)
#define SRAM_FLASHRAM_ADDRESS (0x03FE0000) #define SRAM_FLASHRAM_ADDRESS (0x03FE0000)
#define EEPROM_4K_LENGTH (512) #define EEPROM_4K_LENGTH (512)
#define EEPROM_16K_LENGTH (2048) #define EEPROM_16K_LENGTH (2048)
#define SRAM_LENGTH (32 * 1024) #define SRAM_LENGTH (32 * 1024)
#define FLASHRAM_LENGTH (128 * 1024) #define FLASHRAM_LENGTH (128 * 1024)
#define SRAM_BANKED_LENGTH (3 * 32 * 1024) #define SRAM_BANKED_LENGTH (3 * 32 * 1024)
#define SRAM_1M_LENGTH (128 * 1024) #define SRAM_1M_LENGTH (128 * 1024)
#define WRITEBACK_DELAY_TICKS (100)
#define WRITEBACK_DELAY_MS (1000)
struct process { struct process {
@ -78,9 +82,14 @@ static void writeback_save_to_sd (void) {
return; return;
} }
if(sd_optimize_sectors(address, p.sectors, length / SD_SECTOR_SIZE, sd_write_sectors)) { bool error = sd_optimize_sectors(address, p.sectors, (length / SD_SECTOR_SIZE), sd_write_sectors);
if (error) {
writeback_disable(); writeback_disable();
return;
} }
led_activity_pulse();
} }
static bool writeback_save_to_usb (void) { static bool writeback_save_to_usb (void) {
@ -100,7 +109,13 @@ static bool writeback_save_to_usb (void) {
packet_info.data[0] = save; packet_info.data[0] = save;
packet_info.dma_length = length; packet_info.dma_length = length;
packet_info.dma_address = address; packet_info.dma_address = address;
return usb_enqueue_packet(&packet_info); bool enqueued = usb_enqueue_packet(&packet_info);
if (enqueued) {
led_activity_pulse();
}
return enqueued;
} }
@ -111,6 +126,7 @@ void writeback_load_sector_table (uint32_t address) {
} }
} }
void writeback_enable (writeback_mode_t mode) { void writeback_enable (writeback_mode_t mode) {
p.enabled = true; p.enabled = true;
p.pending = false; p.pending = false;
@ -121,13 +137,14 @@ void writeback_enable (writeback_mode_t mode) {
void writeback_disable (void) { void writeback_disable (void) {
p.enabled = false; p.enabled = false;
p.pending = false; p.pending = false;
timer_set(TIMER_ID_WRITEBACK, 0); timer_countdown_abort(TIMER_ID_WRITEBACK);
} }
bool writeback_pending (void) { bool writeback_pending (void) {
return p.enabled && p.pending; return p.enabled && p.pending;
} }
void writeback_init (void) { void writeback_init (void) {
p.enabled = false; p.enabled = false;
p.pending = false; p.pending = false;
@ -137,6 +154,7 @@ void writeback_init (void) {
} }
} }
void writeback_process (void) { void writeback_process (void) {
if (p.enabled && (p.mode == WRITEBACK_SD) && !sd_card_is_inserted()) { if (p.enabled && (p.mode == WRITEBACK_SD) && !sd_card_is_inserted()) {
writeback_disable(); writeback_disable();
@ -144,24 +162,27 @@ void writeback_process (void) {
if (p.enabled) { if (p.enabled) {
uint16_t save_count = fpga_reg_get(REG_SAVE_COUNT); uint16_t save_count = fpga_reg_get(REG_SAVE_COUNT);
if (save_count != p.last_save_count) { if (save_count != p.last_save_count) {
p.pending = true; p.pending = true;
p.last_save_count = save_count; 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) { switch (p.mode) {
case WRITEBACK_SD: case WRITEBACK_SD:
writeback_save_to_sd(); writeback_save_to_sd();
p.pending = false; p.pending = false;
break; break;
case WRITEBACK_USB: case WRITEBACK_USB:
if (writeback_save_to_usb()) { if (writeback_save_to_usb()) {
p.pending = false; p.pending = false;
} }
break; break;
default: default:
writeback_disable(); writeback_disable();
break; break;

View File

@ -16,10 +16,13 @@ typedef enum {
void writeback_load_sector_table (uint32_t address); void writeback_load_sector_table (uint32_t address);
void writeback_enable (writeback_mode_t mode); void writeback_enable (writeback_mode_t mode);
void writeback_disable (void); void writeback_disable (void);
bool writeback_pending (void); bool writeback_pending (void);
void writeback_init (void); void writeback_init (void);
void writeback_process (void); void writeback_process (void);

958
sw/deployer/Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -20,8 +20,8 @@ include-flate = { version = "0.2.0", features = ["stable"] }
md5 = "0.7.0" md5 = "0.7.0"
panic-message = "0.3.0" panic-message = "0.3.0"
rust-ini = "0.18.0" rust-ini = "0.18.0"
serial2 = "0.1.7" serial2 = "0.2.17"
serialport = "4.2.0" serialport = "4.3.0"
[profile.release] [profile.release]
lto = true lto = true

View File

@ -166,6 +166,20 @@ const MAX_PACKET_LENGTH: usize = 8 * 1024 * 1024;
const SUPPORTED_USB_PROTOCOL_VERSION: u16 = 2; const SUPPORTED_USB_PROTOCOL_VERSION: u16 = 2;
impl Handler { impl Handler {
pub fn new() -> Self {
let (line_tx, line_rx) = channel::<String>();
let external_line_tx = line_tx.clone();
spawn(move || stdin_thread(line_tx));
Handler {
header: None,
line_rx,
external_line_tx,
encoding: Encoding::UTF8,
}
}
pub fn set_text_encoding(&mut self, encoding: Encoding) { pub fn set_text_encoding(&mut self, encoding: Encoding) {
self.encoding = encoding; self.encoding = encoding;
} }
@ -391,20 +405,6 @@ impl Handler {
} }
} }
pub fn new() -> Handler {
let (line_tx, line_rx) = channel::<String>();
let external_line_tx = line_tx.clone();
spawn(move || stdin_thread(line_tx));
Handler {
header: None,
line_rx,
external_line_tx,
encoding: Encoding::UTF8,
}
}
fn load_file(path: &str) -> Result<Vec<u8>, String> { fn load_file(path: &str) -> Result<Vec<u8>, String> {
if path.len() == 0 { if path.len() == 0 {
return Err(format!("Couldn't open file: Specified path is empty")); return Err(format!("Couldn't open file: Specified path is empty"));

View File

@ -417,7 +417,7 @@ fn handle_64dd_command(connection: Connection, args: &_64DDArgs) -> Result<(), s
let mut sc64 = init_sc64(connection, true)?; let mut sc64 = init_sc64(connection, true)?;
let mut debug_handler = debug::new(); let mut debug_handler = debug::Handler::new();
println!( println!(
"{}\n{}\n{}\n{}", "{}\n{}\n{}\n{}",
@ -627,7 +627,7 @@ fn handle_64dd_command(connection: Connection, args: &_64DDArgs) -> Result<(), s
fn handle_debug_command(connection: Connection, args: &DebugArgs) -> Result<(), sc64::Error> { fn handle_debug_command(connection: Connection, args: &DebugArgs) -> Result<(), sc64::Error> {
let mut sc64 = init_sc64(connection, true)?; let mut sc64 = init_sc64(connection, true)?;
let mut debug_handler = debug::new(); let mut debug_handler = debug::Handler::new();
if args.euc_jp { if args.euc_jp {
debug_handler.set_text_encoding(debug::Encoding::EUCJP); debug_handler.set_text_encoding(debug::Encoding::EUCJP);
@ -738,7 +738,7 @@ fn handle_info_command(connection: Connection) -> Result<(), sc64::Error> {
println!(" LED blink: {}", state.led_enable); println!(" LED blink: {}", state.led_enable);
println!(" IS-Viewer 64 offset: 0x{:08X}", state.isv_address); println!(" IS-Viewer 64 offset: 0x{:08X}", state.isv_address);
println!(" FPGA debug data: {}", state.fpga_debug_data); println!(" FPGA debug data: {}", state.fpga_debug_data);
println!(" MCU stack usage: {}", state.mcu_stack_usage); println!(" Diagnostic data: {}", state.diagnostic_data);
Ok(()) Ok(())
} }
@ -859,7 +859,7 @@ fn handle_server_command(connection: Connection, args: &ServerArgs) -> Result<()
None None
}; };
sc64::run_server(port, args.address.clone(), |event| match event { sc64::server::run(port, args.address.clone(), |event| match event {
sc64::ServerEvent::Listening(address) => { sc64::ServerEvent::Listening(address) => {
println!( println!(
"{}: Listening on address [{}]", "{}: Listening on address [{}]",
@ -895,8 +895,8 @@ fn handle_server_command(connection: Connection, args: &ServerArgs) -> Result<()
fn init_sc64(connection: Connection, check_firmware: bool) -> Result<sc64::SC64, sc64::Error> { fn init_sc64(connection: Connection, check_firmware: bool) -> Result<sc64::SC64, sc64::Error> {
let mut sc64 = match connection { let mut sc64 = match connection {
Connection::Local(port) => sc64::new_local(port), Connection::Local(port) => sc64::SC64::open_local(port),
Connection::Remote(remote) => sc64::new_remote(remote), Connection::Remote(remote) => sc64::SC64::open_remote(remote),
}?; }?;
if check_firmware { if check_firmware {

View File

@ -2,7 +2,7 @@ mod cic;
mod error; mod error;
pub mod firmware; pub mod firmware;
mod link; mod link;
mod server; pub mod server;
mod time; mod time;
mod types; mod types;
@ -12,7 +12,7 @@ pub use self::{
server::ServerEvent, server::ServerEvent,
types::{ types::{
BootMode, ButtonMode, ButtonState, CicSeed, DataPacket, DdDiskState, DdDriveType, DdMode, BootMode, ButtonMode, ButtonState, CicSeed, DataPacket, DdDiskState, DdDriveType, DdMode,
DebugPacket, DiskPacket, DiskPacketKind, FpgaDebugData, McuStackUsage, SaveType, DebugPacket, DiagnosticData, DiskPacket, DiskPacketKind, FpgaDebugData, SaveType,
SaveWriteback, Switch, TvType, SaveWriteback, Switch, TvType,
}, },
}; };
@ -55,7 +55,7 @@ pub struct DeviceState {
pub led_enable: Switch, pub led_enable: Switch,
pub datetime: DateTime<Local>, pub datetime: DateTime<Local>,
pub fpga_debug_data: FpgaDebugData, pub fpga_debug_data: FpgaDebugData,
pub mcu_stack_usage: McuStackUsage, pub diagnostic_data: DiagnosticData,
} }
const SC64_V2_IDENTIFIER: &[u8; 4] = b"SCv2"; const SC64_V2_IDENTIFIER: &[u8; 4] = b"SCv2";
@ -350,7 +350,7 @@ impl SC64 {
Ok(u32::from_be_bytes(data[0..4].try_into().unwrap()).try_into()?) Ok(u32::from_be_bytes(data[0..4].try_into().unwrap()).try_into()?)
} }
fn command_debug_get(&mut self) -> Result<FpgaDebugData, Error> { fn command_fpga_debug_data_get(&mut self) -> Result<FpgaDebugData, Error> {
let data = self.link.execute_command(&Command { let data = self.link.execute_command(&Command {
id: b'?', id: b'?',
args: [0, 0], args: [0, 0],
@ -359,7 +359,7 @@ impl SC64 {
Ok(data.try_into()?) Ok(data.try_into()?)
} }
fn command_stack_usage_get(&mut self) -> Result<McuStackUsage, Error> { fn command_diagnostic_data_get(&mut self) -> Result<DiagnosticData, Error> {
let data = self.link.execute_command(&Command { let data = self.link.execute_command(&Command {
id: b'%', id: b'%',
args: [0, 0], args: [0, 0],
@ -557,8 +557,8 @@ impl SC64 {
rom_extended_enable: get_config!(self, RomExtendedEnable)?, rom_extended_enable: get_config!(self, RomExtendedEnable)?,
led_enable: get_setting!(self, LedEnable)?, led_enable: get_setting!(self, LedEnable)?,
datetime: self.get_datetime()?, datetime: self.get_datetime()?,
fpga_debug_data: self.command_debug_get()?, fpga_debug_data: self.command_fpga_debug_data_get()?,
mcu_stack_usage: self.command_stack_usage_get()?, diagnostic_data: self.command_diagnostic_data_get()?,
}) })
} }
@ -787,7 +787,8 @@ impl SC64 {
} }
} }
pub fn new_local(port: Option<String>) -> Result<SC64, Error> { impl SC64 {
pub fn open_local(port: Option<String>) -> Result<Self, Error> {
let port = if let Some(port) = port { let port = if let Some(port) = port {
port port
} else { } else {
@ -798,25 +799,13 @@ pub fn new_local(port: Option<String>) -> Result<SC64, Error> {
}; };
sc64.check_device()?; sc64.check_device()?;
Ok(sc64) Ok(sc64)
} }
pub fn new_remote(address: String) -> Result<SC64, Error> { pub fn open_remote(address: String) -> Result<Self, Error> {
let mut sc64 = SC64 { let mut sc64 = SC64 {
link: link::new_remote(&address)?, link: link::new_remote(&address)?,
}; };
sc64.check_device()?; sc64.check_device()?;
Ok(sc64) Ok(sc64)
} }
pub fn run_server(
port: Option<String>,
address: String,
event_callback: fn(ServerEvent),
) -> Result<(), Error> {
let port = if let Some(port) = port {
port
} else {
list_local_devices()?[0].port.clone()
};
server::run_server(&port, address, event_callback)
} }

View File

@ -1,6 +1,6 @@
use super::{ use super::{
error::Error, error::Error,
link::{new_serial, Command, DataType, Packet, Response, Serial}, link::{list_local_devices, new_serial, Command, DataType, Packet, Response, Serial},
}; };
use std::{ use std::{
collections::VecDeque, collections::VecDeque,
@ -22,11 +22,16 @@ pub enum ServerEvent {
Err(String), Err(String),
} }
pub fn run_server( pub fn run(
port: &str, port: Option<String>,
address: String, address: String,
event_callback: fn(ServerEvent), event_callback: fn(ServerEvent),
) -> Result<(), Error> { ) -> Result<(), Error> {
let port = if let Some(port) = port {
port
} else {
list_local_devices()?[0].port.clone()
};
let listener = TcpListener::bind(address)?; let listener = TcpListener::bind(address)?;
let listening_address = listener.local_addr()?; let listening_address = listener.local_addr()?;
event_callback(ServerEvent::Listening(listening_address.to_string())); event_callback(ServerEvent::Listening(listening_address.to_string()));
@ -36,7 +41,7 @@ pub fn run_server(
Ok(mut stream) => { Ok(mut stream) => {
let peer = stream.peer_addr()?.to_string(); let peer = stream.peer_addr()?.to_string();
event_callback(ServerEvent::Connected(peer.clone())); event_callback(ServerEvent::Connected(peer.clone()));
match server_accept_connection(port, &mut stream) { match server_accept_connection(port.clone(), &mut stream) {
Ok(()) => event_callback(ServerEvent::Disconnected(peer.clone())), Ok(()) => event_callback(ServerEvent::Disconnected(peer.clone())),
Err(error) => event_callback(ServerEvent::Err(error.to_string())), Err(error) => event_callback(ServerEvent::Err(error.to_string())),
} }
@ -58,14 +63,14 @@ enum Event {
Closed(Option<Error>), Closed(Option<Error>),
} }
fn server_accept_connection(port: &str, stream: &mut TcpStream) -> Result<(), Error> { fn server_accept_connection(port: String, stream: &mut TcpStream) -> Result<(), Error> {
let (event_sender, event_receiver) = channel::<Event>(); let (event_sender, event_receiver) = channel::<Event>();
let exit_flag = Arc::new(AtomicBool::new(false)); let exit_flag = Arc::new(AtomicBool::new(false));
let mut stream_writer = BufWriter::new(stream.try_clone()?); let mut stream_writer = BufWriter::new(stream.try_clone()?);
let mut stream_reader = stream.try_clone()?; let mut stream_reader = stream.try_clone()?;
let serial = Arc::new(new_serial(port)?); let serial = Arc::new(new_serial(&port)?);
let serial_writer = serial.clone(); let serial_writer = serial.clone();
let serial_reader = serial.clone(); let serial_reader = serial.clone();

View File

@ -828,38 +828,82 @@ impl Display for FpgaDebugData {
} }
} }
pub struct McuStackUsage { pub struct DiagnosticDataV0 {
pub cic: u32, pub cic: u32,
pub rtc: u32, pub rtc: u32,
pub led: u32, pub led: u32,
pub gvr: u32, pub gvr: u32,
} }
impl TryFrom<Vec<u8>> for McuStackUsage { pub struct DiagnosticDataV1 {
pub voltage: f32,
pub temperature: f32,
}
pub enum DiagnosticData {
V0(DiagnosticDataV0),
V1(DiagnosticDataV1),
Unknown,
}
impl TryFrom<Vec<u8>> for DiagnosticData {
type Error = Error; type Error = Error;
fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> { fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> {
if value.len() != 16 { if value.len() < 4 {
return Err(Error::new("Invalid data length for MCU stack usage")); return Err(Error::new("Invalid data length for diagnostic data"));
} }
Ok(McuStackUsage { let raw_version = u32::from_be_bytes(value[0..4].try_into().unwrap());
let unversioned = raw_version & (1 << 31) == 0;
let version = raw_version & !(1 << 31);
if unversioned {
if value.len() != 16 {
return Err(Error::new("Invalid data length for V0 diagnostic data"));
}
return Ok(DiagnosticData::V0(DiagnosticDataV0 {
cic: u32::from_be_bytes(value[0..4].try_into().unwrap()), cic: u32::from_be_bytes(value[0..4].try_into().unwrap()),
rtc: u32::from_be_bytes(value[4..8].try_into().unwrap()), rtc: u32::from_be_bytes(value[4..8].try_into().unwrap()),
led: u32::from_be_bytes(value[8..12].try_into().unwrap()), led: u32::from_be_bytes(value[8..12].try_into().unwrap()),
gvr: u32::from_be_bytes(value[12..16].try_into().unwrap()), gvr: u32::from_be_bytes(value[12..16].try_into().unwrap()),
}) }));
}
match version {
1 => {
if value.len() != 16 {
return Err(Error::new("Invalid data length for V1 diagnostic data"));
}
let raw_voltage = u32::from_be_bytes(value[4..8].try_into().unwrap()) as f32;
let raw_temperature = u32::from_be_bytes(value[8..12].try_into().unwrap()) as f32;
Ok(DiagnosticData::V1(DiagnosticDataV1 {
voltage: raw_voltage / 1000.0,
temperature: raw_temperature / 10.0,
}))
}
_ => Ok(DiagnosticData::Unknown),
}
} }
} }
impl Display for McuStackUsage { impl Display for DiagnosticData {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if self.cic > 0 { match self {
f.write_fmt(format_args!("CIC: {}, ", self.cic))?; DiagnosticData::V0(d) => {
if d.cic > 0 {
f.write_fmt(format_args!("CIC: {}, ", d.cic))?;
} }
f.write_fmt(format_args!( f.write_fmt(format_args!(
"RTC: {}, LED: {}, GVR: {}", "RTC: {}, LED: {}, GVR: {}",
self.rtc, self.led, self.gvr d.rtc, d.led, d.gvr
)) ))
} }
DiagnosticData::V1(d) => f.write_fmt(format_args!(
"{:.03} V / {:.01} °C",
d.voltage, d.temperature
)),
DiagnosticData::Unknown => f.write_str("Unknown"),
}
}
} }
macro_rules! get_config { macro_rules! get_config {
@ -874,7 +918,7 @@ macro_rules! get_config {
macro_rules! get_setting { macro_rules! get_setting {
($sc64:ident, $setting:ident) => {{ ($sc64:ident, $setting:ident) => {{
// Note: remove 'allow(irrefutable_let_patterns)' below when more settings are added // NOTE: remove 'allow(irrefutable_let_patterns)' below when more settings are added
#[allow(irrefutable_let_patterns)] #[allow(irrefutable_let_patterns)]
if let Setting::$setting(value) = $sc64.command_setting_get(SettingId::$setting)? { if let Setting::$setting(value) = $sc64.command_setting_get(SettingId::$setting)? {
Ok(value) Ok(value)

View File

@ -204,9 +204,16 @@ class STM32Bootloader:
__connected = False __connected = False
def __init__(self, write: Callable[[bytes], None], read: Callable[[int], bytes], progress: Callable[[int, int, str], None]): def __init__(
self,
write: Callable[[bytes], None],
read: Callable[[int], bytes],
flush: Callable[[None], None],
progress: Callable[[int, int, str], None]
):
self.__write = write self.__write = write
self.__read = read self.__read = read
self.__flush = flush
self.__progress = progress self.__progress = progress
def __append_xor(self, data: bytes) -> bytes: def __append_xor(self, data: bytes) -> bytes:
@ -217,7 +224,7 @@ class STM32Bootloader:
def __check_ack(self) -> None: def __check_ack(self) -> None:
response = self.__read(1) response = self.__read(1)
if (response == None): if (len(response) != 1):
raise STM32BootloaderException('No ACK/NACK byte received') raise STM32BootloaderException('No ACK/NACK byte received')
if (response == self.__NACK): if (response == self.__NACK):
raise STM32BootloaderException('NACK byte received') raise STM32BootloaderException('NACK byte received')
@ -228,18 +235,22 @@ class STM32Bootloader:
if (len(cmd) != 1): if (len(cmd) != 1):
raise ValueError('Command must contain only one byte') raise ValueError('Command must contain only one byte')
self.__write(self.__append_xor(cmd)) self.__write(self.__append_xor(cmd))
self.__flush()
self.__check_ack() self.__check_ack()
def __data_write(self, data: bytes) -> None: def __data_write(self, data: bytes) -> None:
self.__write(self.__append_xor(data)) self.__write(self.__append_xor(data))
self.__flush()
self.__check_ack() self.__check_ack()
def __data_read(self) -> bytes: def __data_read(self) -> bytes:
length = self.__read(1) length = self.__read(1)
if (len(length) != 1): if (len(length) != 1):
raise STM32BootloaderException('Did not receive length byte') raise STM32BootloaderException('Did not receive length byte')
length = length[0] length = (length[0] + 1)
data = self.__read(length + 1) data = self.__read(length)
if (len(data) != length):
raise STM32BootloaderException('Did not receive requested data bytes')
self.__check_ack() self.__check_ack()
return data return data
@ -253,7 +264,10 @@ class STM32Bootloader:
self.__cmd_send(b'\x11') self.__cmd_send(b'\x11')
self.__data_write(address.to_bytes(4, byteorder='big')) self.__data_write(address.to_bytes(4, byteorder='big'))
self.__data_write(bytes([length - 1])) self.__data_write(bytes([length - 1]))
return self.__read(length) data = self.__read(length)
if (len(data) != length):
raise STM32BootloaderException(f'Did not receive requested memory bytes')
return data
def __go(self, address: int) -> None: def __go(self, address: int) -> None:
self.__cmd_send(b'\x21') self.__cmd_send(b'\x21')
@ -288,8 +302,12 @@ class STM32Bootloader:
def connect(self, id: int) -> None: def connect(self, id: int) -> None:
if (not self.__connected): if (not self.__connected):
try:
self.__write(self.__INIT) self.__write(self.__INIT)
self.__flush()
self.__check_ack() self.__check_ack()
except STM32BootloaderException as e:
raise STM32BootloaderException(f'Could not connect to the STM32 ({e})')
self.__connected = True self.__connected = True
dev_id = self.__get_id() dev_id = self.__get_id()
if (dev_id != id): if (dev_id != id):
@ -339,9 +357,16 @@ class LCMXO2Primer:
DEV_ID_LCMXO2_7000HC = b'\x01\x2B\xD0\x43' DEV_ID_LCMXO2_7000HC = b'\x01\x2B\xD0\x43'
def __init__(self, write: Callable[[bytes], None], read: Callable[[int], bytes], progress: Callable[[int, int, str], None]): def __init__(
self,
write: Callable[[bytes], None],
read: Callable[[int], bytes],
flush: Callable[[None], None],
progress: Callable[[int, int, str], None]
):
self.__write = write self.__write = write
self.__read = read self.__read = read
self.__flush = flush
self.__progress = progress self.__progress = progress
def __cmd_execute(self, cmd: bytes, data: bytes=b'') -> bytes: def __cmd_execute(self, cmd: bytes, data: bytes=b'') -> bytes:
@ -355,14 +380,20 @@ class LCMXO2Primer:
packet += data packet += data
packet += crc32(packet).to_bytes(4, byteorder='little') packet += crc32(packet).to_bytes(4, byteorder='little')
self.__write(packet) self.__write(packet)
self.__flush()
response = self.__read(5) response = self.__read(5)
if (len(response) != 5): if (len(response) != 5):
raise LCMXO2PrimerException(f'No response received [{cmd}]') raise LCMXO2PrimerException(f'No response received [{cmd}]')
length = int.from_bytes(response[4:5], byteorder='little') length = int.from_bytes(response[4:5], byteorder='little')
response += self.__read(length) response_data = self.__read(length)
calculated_checksum = crc32(response) if (len(response_data) != length):
received_checksum = int.from_bytes(self.__read(4), byteorder='little') raise LCMXO2PrimerException(f'No response data received [{cmd}]')
checksum = self.__read(4)
if (len(checksum) != 4):
raise LCMXO2PrimerException(f'No response data checksum received [{cmd}]')
calculated_checksum = crc32(response + response_data)
received_checksum = int.from_bytes(checksum, byteorder='little')
if (response[0:3] != b'RSP'): if (response[0:3] != b'RSP'):
raise LCMXO2PrimerException(f'Invalid response token [{response[0:3]} / {cmd}]') raise LCMXO2PrimerException(f'Invalid response token [{response[0:3]} / {cmd}]')
@ -371,9 +402,10 @@ class LCMXO2Primer:
if (calculated_checksum != received_checksum): if (calculated_checksum != received_checksum):
raise LCMXO2PrimerException(f'Invalid response checksum [{cmd}]') raise LCMXO2PrimerException(f'Invalid response checksum [{cmd}]')
return response[5:] return response_data
def connect(self, id: bytes) -> None: def connect(self, id: bytes) -> None:
try:
primer_id = self.__cmd_execute(self.__CMD_GET_PRIMER_ID) primer_id = self.__cmd_execute(self.__CMD_GET_PRIMER_ID)
if (primer_id != self.__PRIMER_ID_LCMXO2): if (primer_id != self.__PRIMER_ID_LCMXO2):
raise LCMXO2PrimerException('Invalid primer ID received') raise LCMXO2PrimerException('Invalid primer ID received')
@ -381,6 +413,8 @@ class LCMXO2Primer:
dev_id = self.__cmd_execute(self.__CMD_GET_DEVICE_ID) dev_id = self.__cmd_execute(self.__CMD_GET_DEVICE_ID)
if (dev_id != id): if (dev_id != id):
raise LCMXO2PrimerException('Invalid FPGA device id received') raise LCMXO2PrimerException('Invalid FPGA device id received')
except LCMXO2PrimerException as e:
raise LCMXO2PrimerException(f'Could not connect to the LCMXO2 primer ({e})')
def load_flash_and_run(self, data: bytes, description: str) -> None: def load_flash_and_run(self, data: bytes, description: str) -> None:
erase_description = f'{description} / Erase' erase_description = f'{description} / Erase'
@ -599,8 +633,8 @@ class SC64BringUp:
write_timeout=self.__SERIAL_TIMEOUT write_timeout=self.__SERIAL_TIMEOUT
) )
stm32_bootloader = STM32Bootloader(link.write, link.read, self.__progress) stm32_bootloader = STM32Bootloader(link.write, link.read, link.flush, self.__progress)
lcmxo2_primer = LCMXO2Primer(link.write, link.read, self.__progress) lcmxo2_primer = LCMXO2Primer(link.write, link.read, link.flush, self.__progress)
stm32_bootloader.connect(stm32_bootloader.DEV_ID_STM32G030XX) stm32_bootloader.connect(stm32_bootloader.DEV_ID_STM32G030XX)
stm32_bootloader.load_ram_and_run(self.__sc64_update_data.get_primer_data(), 'FPGA primer -> STM32 RAM') stm32_bootloader.load_ram_and_run(self.__sc64_update_data.get_primer_data(), 'FPGA primer -> STM32 RAM')
@ -645,7 +679,7 @@ if __name__ == '__main__':
sc64_bring_up = SC64BringUp(progress=utils.progress) sc64_bring_up = SC64BringUp(progress=utils.progress)
Utils.log() Utils.log()
Utils.info('[ Welcome to SC64 flashcart board bring-up! ]') Utils.info('[ Welcome to the SummerCart64 flashcart board bring-up! ]')
Utils.log() Utils.log()
Utils.log(f'Serial port: {port}') Utils.log(f'Serial port: {port}')
@ -683,6 +717,7 @@ if __name__ == '__main__':
original_sigint_handler = signal.getsignal(signal.SIGINT) original_sigint_handler = signal.getsignal(signal.SIGINT)
try: try:
signal.signal(signal.SIGINT, lambda *kwargs: utils.exit_warning()) signal.signal(signal.SIGINT, lambda *kwargs: utils.exit_warning())
Utils.log('Starting SC64 flashcart board bring-up...')
sc64_bring_up.start_bring_up(port, bootloader_only) sc64_bring_up.start_bring_up(port, bootloader_only)
except (serial.SerialException, STM32BootloaderException, LCMXO2PrimerException, SC64Exception) as e: except (serial.SerialException, STM32BootloaderException, LCMXO2PrimerException, SC64Exception) as e:
if (utils.get_progress_active): if (utils.get_progress_active):