[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 () {
if [ "$BUILT_FPGA" = true ]; then return; fi
build_cic
pushd fw/project/lcmxo2 > /dev/null
if [ "$FORCE_CLEAN" = true ]; then
rm -rf ./impl1/

View File

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

View File

@ -5,7 +5,7 @@
## N64 commands
| id | name | arg0 | arg1 | rsp0 | rsp1 | description |
| --- | --------------------- | -------------- | ------------ | ---------------- | -------------- | ---------------------------------------------------------- |
| --- | --------------------- | ------------- | ------------ | ---------------- | -------------- | ---------------------------------------------------------- |
| `v` | **IDENTIFIER_GET** | --- | --- | identifier | --- | Get flashcart identifier `SCv2` |
| `V` | **VERSION_GET** | --- | --- | major/minor | revision | Get flashcart firmware version |
| `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 |
| `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 |
| `%` | **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_UPDATE** | address | length | --- | status | Update firmware from specified memory address |
| `?` | **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,
n64_scb.flashram_write_or_erase,
n64_scb.flashram_sector_or_all,
n64_scb.flashram_sector,
n64_scb.flashram_page,
n64_scb.flashram_pending,
1'b0
};

View File

@ -8,7 +8,7 @@ module n64_flashram (
);
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] {
CMD_STATUS_MODE = 8'hD2,
@ -97,14 +97,14 @@ module n64_flashram (
CMD_ERASE_SECTOR: begin
state <= STATE_STATUS;
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;
end
CMD_ERASE_CHIP: begin
state <= STATE_STATUS;
erase_enabled <= 1'b1;
n64_scb.flashram_sector <= 10'd0;
n64_scb.flashram_page <= 10'd0;
n64_scb.flashram_sector_or_all <= 1'b1;
end
@ -126,7 +126,7 @@ module n64_flashram (
state <= STATE_STATUS;
status[WRITE_BUSY] <= 1'b1;
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_write_or_erase <= 1'b0;
n64_scb.flashram_sector_or_all <= 1'b0;
@ -134,9 +134,9 @@ module n64_flashram (
endcase
end
end else begin
if (reg_bus.address[1] && state != STATE_BUFFER) begin
status[ERASE_BUSY] <= reg_bus.wdata[ERASE_BUSY];
status[WRITE_BUSY] <= reg_bus.wdata[WRITE_BUSY];
if (reg_bus.address[1] && state == STATE_STATUS) begin
status[ERASE_DONE] <= 1'b0;
status[WRITE_DONE] <= 1'b0;
end
end
end

View File

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

View File

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

View File

@ -68,7 +68,7 @@ const uint8_t font_data[96][FONT_CHAR_BYTES] = {
{ 0x38, 0x30, 0x30, 0x30, 0x30, 0x30, 0x38, 0x00, },
{ 0x00, 0x38, 0x6C, 0x00, 0x00, 0x00, 0x00, 0x00, },
{ 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, },
{ 0x06, 0x06, 0x3E, 0x66, 0x66, 0x66, 0x3E, 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_WAIT_BUSY = 'p',
CMD_ID_FLASH_ERASE_BLOCK = 'P',
CMD_ID_DIAGNOSTIC_GET = '%',
} sc64_cmd_id_t;
typedef enum {
@ -436,3 +437,14 @@ sc64_error_t sc64_flash_erase_block (void *address) {
};
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,
} sc64_button_mode_t;
typedef enum {
DIAGNOSTIC_ID_VOLTAGE_TEMPERATURE,
} sc64_diagnostic_id_t;
typedef struct {
sc64_boot_mode_t boot_mode;
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_erase_block (void *address);
sc64_error_t sc64_get_diagnostic (sc64_diagnostic_id_t id, uint32_t *value);
#endif

View File

@ -10,10 +10,22 @@
static void test_sc64_cfg (void) {
sc64_error_t error;
uint32_t button_state;
uint32_t identifier;
uint16_t major;
uint16_t minor;
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) {
error_display("Command IDENTIFIER_GET failed: %d", error);
@ -25,9 +37,19 @@ static void test_sc64_cfg (void) {
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) {
@ -233,7 +255,7 @@ bool test_check (void) {
error_display("Command CONFIG_GET [BUTTON_STATE] failed: %d", error);
}
return button_state != 0;
return (button_state != 0);
}
static struct {

View File

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

View File

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

View File

@ -1,34 +1,51 @@
#include "app.h"
#include "gvr.h"
#include <stdbool.h>
#include "button.h"
#include "cfg.h"
#include "cic.h"
#include "dd.h"
#include "flashram.h"
#include "fpga.h"
#include "hw.h"
#include "isv.h"
#include "led.h"
#include "rtc.h"
#include "task.h"
#include "sd.h"
#include "timer.h"
#include "usb.h"
#include "writeback.h"
#define RTC_STACK_SIZE (256)
#define LED_STACK_SIZE (256)
#define GVR_STACK_SIZE (2048)
uint8_t rtc_stack[RTC_STACK_SIZE] __attribute__((aligned(8)));
uint8_t led_stack[LED_STACK_SIZE] __attribute__((aligned(8)));
uint8_t gvr_stack[GVR_STACK_SIZE] __attribute__((aligned(8)));
void app_get_stack_usage (uint32_t *usage) {
*usage++ = 0;
*usage++ = task_get_stack_usage(rtc_stack, RTC_STACK_SIZE);
*usage++ = task_get_stack_usage(led_stack, LED_STACK_SIZE);
*usage++ = task_get_stack_usage(gvr_stack, GVR_STACK_SIZE);
}
void app (void) {
hw_init();
hw_app_init();
task_create(TASK_ID_RTC, rtc_task, rtc_stack, RTC_STACK_SIZE);
task_create(TASK_ID_LED, led_task, led_stack, LED_STACK_SIZE);
task_create(TASK_ID_GVR, gvr_task, gvr_stack, GVR_STACK_SIZE);
timer_init();
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) {
if (mode > BUTTON_MODE_DD_DISK_SWAP) {
if (mode >= __BUTTON_MODE_COUNT) {
return true;
}
p.mode = mode;
@ -39,6 +39,7 @@ button_mode_t button_get_mode (void) {
return p.mode;
}
void button_init (void) {
p.counter = 0;
p.state = false;
@ -46,9 +47,12 @@ void button_init (void) {
p.trigger = false;
}
void button_process (void) {
usb_tx_info_t packet_info;
uint32_t status = fpga_reg_get(REG_CFG_SCR);
if (status & CFG_SCR_BUTTON_STATE) {
if (p.counter < BUTTON_COUNTER_TRIGGER_ON) {
p.counter += 1;
@ -58,13 +62,16 @@ void button_process (void) {
p.counter -= 1;
}
}
if (!p.state && p.counter == BUTTON_COUNTER_TRIGGER_ON) {
p.state = true;
p.trigger = true;
}
if (p.state && p.counter == BUTTON_COUNTER_TRIGGER_OFF) {
p.state = false;
}
if (p.trigger) {
switch (p.mode) {
case BUTTON_MODE_N64_IRQ:

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -9,15 +9,15 @@
#define FLASHRAM_BUFFER_ADDRESS (0x05002900UL)
enum operation {
typedef enum {
OP_NONE,
OP_ERASE_ALL,
OP_ERASE_SECTOR,
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)) {
return OP_NONE;
}
@ -40,40 +40,47 @@ void flashram_init (void) {
}
}
void flashram_process (void) {
uint32_t scr = fpga_reg_get(REG_FLASHRAM_SCR);
enum operation op = flashram_operation_type(scr);
uint8_t read_buffer[FLASHRAM_PAGE_SIZE];
uint8_t 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) {
case OP_ERASE_ALL:
case OP_ERASE_SECTOR:
flashram_op_t op = flashram_operation_type(scr);
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++) {
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:
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;
page &= ~((FLASHRAM_SECTOR_SIZE / FLASHRAM_PAGE_SIZE) - 1);
case OP_NONE:
default:
break;
uint32_t erase_size = (op == OP_ERASE_ALL) ? FLASHRAM_SIZE : FLASHRAM_SECTOR_SIZE;
uint32_t address = (FLASHRAM_ADDRESS + (page * FLASHRAM_PAGE_SIZE));
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_process (void);

View File

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

View File

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

View File

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

View File

@ -1,9 +1,134 @@
#include <stdbool.h>
#include <stddef.h>
#include <stm32g0xx.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 {
@ -42,22 +167,7 @@ typedef enum {
GPIO_AF_7 = 0x07
} gpio_af_t;
typedef struct {
void (*volatile falling)(void);
void (*volatile rising)(void);
} gpio_irq_callback_t;
static const GPIO_TypeDef *gpios[] = { GPIOA, GPIOB, 0, 0, 0, 0, 0, 0 };
static gpio_irq_callback_t gpio_irq_callbacks[16];
static volatile uint8_t *i2c_data_txptr;
static volatile uint8_t *i2c_data_rxptr;
static volatile uint32_t i2c_next_cr2;
static void (*volatile i2c_callback)(void);
static const TIM_TypeDef *tims[] = { TIM14, TIM16, TIM17, TIM3, TIM1 };
static void (*volatile tim_callbacks[5])(void);
static void hw_gpio_init (gpio_id_t id, gpio_mode_t mode, gpio_ot_t ot, gpio_ospeed_t ospeed, gpio_pupd_t pupd, gpio_af_t af, int value) {
GPIO_TypeDef tmp;
@ -65,6 +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 afr = ((pin < 8) ? 0 : 1);
RCC->IOPENR |= (RCC_IOPENR_GPIOAEN | RCC_IOPENR_GPIOBEN);
tmp.MODER = (gpio->MODER & ~(GPIO_MODER_MODE0_Msk << (pin * 2)));
tmp.OTYPER = (gpio->OTYPER & ~(GPIO_OTYPER_OT0_Msk << pin));
tmp.OSPEEDR = (gpio->OSPEEDR & ~(GPIO_OSPEEDR_OSPEED0_Msk << (pin * 2)));
@ -80,22 +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)));
}
void hw_gpio_irq_setup (gpio_id_t id, gpio_irq_t irq, void (*callback)(void)) {
uint8_t port = ((id >> 4) & 0x07);
uint8_t pin = (id & 0x0F);
__disable_irq();
if (irq == GPIO_IRQ_FALLING) {
EXTI->FTSR1 |= (EXTI_FTSR1_FT0 << pin);
gpio_irq_callbacks[pin].falling = callback;
} else {
EXTI->RTSR1 |= (EXTI_RTSR1_RT0 << pin);
gpio_irq_callbacks[pin].rising = callback;
}
EXTI->EXTICR[pin / 4] |= (port << (8 * (pin % 4)));
EXTI->IMR1 |= (EXTI_IMR1_IM0 << pin);
__enable_irq();
}
uint32_t hw_gpio_get (gpio_id_t id) {
GPIO_TypeDef *gpio = ((GPIO_TypeDef *) (gpios[(id >> 4) & 0x07]));
uint8_t pin = (id & 0x0F);
@ -114,6 +210,22 @@ void hw_gpio_reset (gpio_id_t id) {
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) {
for (int i = 0; i < length; i++) {
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));
}
static void hw_spi_init (void) {
RCC->AHBENR |= RCC_AHBENR_DMA1EN;
RCC->APBENR2 |= RCC_APBENR2_SPI1EN;
DMAMUX1_Channel0->CCR = (16 << DMAMUX_CxCR_DMAREQ_ID_Pos);
DMAMUX1_Channel1->CCR = (17 << DMAMUX_CxCR_DMAREQ_ID_Pos);
DMA1_Channel1->CPAR = (uint32_t) (&SPI1->DR);
DMA1_Channel2->CPAR = (uint32_t) (&SPI1->DR);
SPI1->CR2 = (
SPI_CR2_FRXTH |
(8 - 1) << SPI_CR2_DS_Pos |
SPI_CR2_TXDMAEN |
SPI_CR2_RXDMAEN
);
SPI1->CR1 = (
SPI_CR1_SSM |
SPI_CR1_SSI |
SPI_CR1_BR_1 |
SPI_CR1_SPE |
SPI_CR1_MSTR |
SPI_CR1_CPHA
);
hw_gpio_init(GPIO_ID_SPI_CS, GPIO_OUTPUT, GPIO_PP, GPIO_SPEED_HIGH, GPIO_PULL_NONE, GPIO_AF_0, 1);
hw_gpio_init(GPIO_ID_SPI_CLK, GPIO_ALT, GPIO_PP, GPIO_SPEED_HIGH, GPIO_PULL_NONE, GPIO_AF_0, 0);
hw_gpio_init(GPIO_ID_SPI_MOSI, GPIO_ALT, GPIO_PP, GPIO_SPEED_HIGH, GPIO_PULL_NONE, GPIO_AF_0, 0);
hw_gpio_init(GPIO_ID_SPI_MISO, GPIO_ALT, GPIO_PP, GPIO_SPEED_HIGH, GPIO_PULL_DOWN, GPIO_AF_0, 0);
}
void hw_spi_start (void) {
hw_gpio_reset(GPIO_ID_SPI_CS);
}
@ -141,25 +285,17 @@ void hw_spi_stop (void) {
hw_gpio_set(GPIO_ID_SPI_CS);
}
void hw_spi_trx (uint8_t *data, int length, spi_direction_t direction) {
volatile uint8_t dummy __attribute__((unused));
void hw_spi_rx (uint8_t *data, int length) {
volatile uint8_t dummy = 0x00;
DMA1_Channel1->CNDTR = length;
DMA1_Channel2->CNDTR = length;
if (direction == SPI_TX) {
DMA1_Channel1->CMAR = (uint32_t) (&dummy);
DMA1_Channel1->CCR = DMA_CCR_EN;
DMA1_Channel2->CMAR = (uint32_t) (data);
DMA1_Channel2->CCR = (DMA_CCR_MINC | DMA_CCR_DIR | DMA_CCR_EN);
} else {
DMA1_Channel1->CMAR = (uint32_t) (data);
DMA1_Channel1->CCR = (DMA_CCR_MINC | DMA_CCR_EN);
DMA1_Channel2->CMAR = (uint32_t) (&dummy);
DMA1_Channel2->CCR = (DMA_CCR_DIR | DMA_CCR_EN);
}
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;
}
void hw_i2c_read (uint8_t i2c_address, uint8_t address, uint8_t *data, uint8_t length, void (*callback)(void)) {
i2c_data_rxptr = data;
i2c_callback = callback;
I2C1->TXDR = address;
i2c_next_cr2 = (
I2C_CR2_AUTOEND |
(length << I2C_CR2_NBYTES_Pos) |
I2C_CR2_START |
I2C_CR2_RD_WRN |
(i2c_address << I2C_CR2_SADD_Pos)
);
I2C1->CR2 = (
(1 << I2C_CR2_NBYTES_Pos) |
I2C_CR2_START |
(i2c_address << I2C_CR2_SADD_Pos)
);
void hw_spi_tx (uint8_t *data, int length) {
volatile uint8_t dummy __attribute__((unused));
DMA1_Channel1->CNDTR = length;
DMA1_Channel2->CNDTR = length;
DMA1_Channel1->CMAR = (uint32_t) (&dummy);
DMA1_Channel1->CCR = DMA_CCR_EN;
DMA1_Channel2->CMAR = (uint32_t) (data);
DMA1_Channel2->CCR = (DMA_CCR_MINC | DMA_CCR_DIR | DMA_CCR_EN);
while (DMA1_Channel1->CNDTR || DMA1_Channel2->CNDTR);
DMA1_Channel1->CCR = 0;
DMA1_Channel2->CCR = 0;
}
void hw_i2c_write (uint8_t i2c_address, uint8_t address, uint8_t *data, uint8_t length, void (*callback)(void)) {
i2c_data_txptr = data;
i2c_callback = callback;
I2C1->TXDR = address;
I2C1->CR2 = (
I2C_CR2_AUTOEND |
((length + 1) << I2C_CR2_NBYTES_Pos) |
I2C_CR2_START |
(i2c_address << I2C_CR2_SADD_Pos)
);
#define I2C_TIMEOUT_US_BUSY (10000)
#define I2C_TIMEOUT_US_PER_BYTE (1000)
static void hw_i2c_init (void) {
RCC->APBENR1 |= RCC_APBENR1_I2C1EN;
I2C1->CR1 = 0;
hw_gpio_init(GPIO_ID_I2C_SCL, GPIO_ALT, GPIO_OD, GPIO_SPEED_VLOW, GPIO_PULL_NONE, GPIO_AF_6, 0);
hw_gpio_init(GPIO_ID_I2C_SDA, GPIO_ALT, GPIO_OD, GPIO_SPEED_VLOW, GPIO_PULL_NONE, GPIO_AF_6, 0);
while (!(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) {
return (I2C1->ISR & I2C_ISR_NACKF);
}
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) {
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) {
uint32_t tx_timeout = ((tx_length + 1) * I2C_TIMEOUT_US_PER_BYTE);
hw_timeout_start();
I2C1->ICR = I2C_ICR_NACKCF;
I2C1->CR2 = (
((rx_length == 0) ? I2C_CR2_AUTOEND : 0) |
((rx_length > 0) ? 0 : I2C_CR2_AUTOEND) |
(tx_length << I2C_CR2_NBYTES_Pos) |
I2C_CR2_START |
(i2c_address << I2C_CR2_SADD_Pos)
(address << I2C_CR2_SADD_Pos)
);
for (int i = 0; i < tx_length; i++) {
while (!(I2C1->ISR & I2C_ISR_TXIS));
uint8_t left = tx_length;
while (left > 0) {
uint32_t isr = I2C1->ISR;
if (isr & I2C_ISR_TXIS) {
I2C1->TXDR = *tx_data++;
left -= 1;
}
if (isr & I2C_ISR_NACKF) {
return I2C_ERR_NACK;
}
if (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) {
uint32_t rx_timeout = ((rx_length + 1) * I2C_TIMEOUT_US_PER_BYTE);
hw_timeout_start();
I2C1->CR2 = (
I2C_CR2_AUTOEND |
(rx_length << I2C_CR2_NBYTES_Pos) |
I2C_CR2_START |
I2C_CR2_RD_WRN |
(i2c_address << I2C_CR2_SADD_Pos)
(address << I2C_CR2_SADD_Pos)
);
for (int i = 0; i < rx_length; i++) {
while (!(I2C1->ISR & I2C_ISR_RXNE));
uint8_t left = rx_length;
while (left > 0) {
uint32_t isr = I2C1->ISR;
if (isr & I2C_ISR_RXNE) {
*rx_data++ = I2C1->RXDR;
left -= 1;
}
if (hw_timeout_occured(rx_timeout)) {
return I2C_ERR_TIMEOUT;
}
}
}
if ((tx_length > 0) || (rx_length > 0)) {
while (!(I2C1->ISR & I2C_ISR_STOPF));
}
return I2C_OK;
}
void hw_i2c_disable_irq (void) {
NVIC_DisableIRQ(I2C1_IRQn);
}
void hw_i2c_enable_irq (void) {
NVIC_EnableIRQ(I2C1_IRQn);
}
static void hw_crc32_init (void) {
RCC->AHBENR |= RCC_AHBENR_CRCEN;
void hw_tim_setup (tim_id_t id, uint16_t delay, void (*callback)(void)) {
if (delay == 0) {
if (callback) {
callback();
}
return;
}
TIM_TypeDef *tim = ((TIM_TypeDef *) (tims[id]));
tim->CR1 = (TIM_CR1_OPM | TIM_CR1_URS);
tim->PSC = (64000 - 1);
tim->ARR = delay;
tim->DIER = TIM_DIER_UIE;
tim->EGR = TIM_EGR_UG;
tim->SR = 0;
tim->CR1 |= TIM_CR1_CEN;
tim_callbacks[id] = callback;
}
void hw_tim_stop (tim_id_t id) {
TIM_TypeDef *tim = ((TIM_TypeDef *) (tims[id]));
tim->CR1 &= ~(TIM_CR1_CEN);
tim_callbacks[id] = 0;
}
void hw_tim_disable_irq (tim_id_t id) {
switch (id) {
case TIM_ID_CIC:
NVIC_DisableIRQ(TIM14_IRQn);
break;
case TIM_ID_RTC:
NVIC_DisableIRQ(TIM16_IRQn);
break;
case TIM_ID_SD:
NVIC_DisableIRQ(TIM17_IRQn);
break;
case TIM_ID_DD:
NVIC_DisableIRQ(TIM3_IRQn);
break;
case TIM_ID_LED:
NVIC_DisableIRQ(TIM1_BRK_UP_TRG_COM_IRQn);
break;
default:
break;
}
}
void hw_tim_enable_irq (tim_id_t id) {
switch (id) {
case TIM_ID_CIC:
NVIC_EnableIRQ(TIM14_IRQn);
break;
case TIM_ID_RTC:
NVIC_EnableIRQ(TIM16_IRQn);
break;
case TIM_ID_SD:
NVIC_EnableIRQ(TIM17_IRQn);
break;
case TIM_ID_DD:
NVIC_EnableIRQ(TIM3_IRQn);
break;
case TIM_ID_LED:
NVIC_EnableIRQ(TIM1_BRK_UP_TRG_COM_IRQn);
break;
default:
break;
}
}
void hw_delay_ms (uint32_t ms) {
SysTick->VAL = 0;
for (uint32_t i = 0; i < ms; i++) {
while (!(SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk));
}
CRC->CR = (CRC_CR_REV_OUT | CRC_CR_REV_IN_0);
}
void hw_crc32_reset (void) {
@ -334,10 +441,15 @@ uint32_t hw_crc32_calculate (uint8_t *data, uint32_t length) {
return (CRC->DR ^ 0xFFFFFFFF);
}
uint32_t hw_flash_size (void) {
return FLASH_SIZE;
}
hw_flash_t hw_flash_read (uint32_t offset) {
return *(uint64_t *) (FLASH_BASE + offset);
}
static void hw_flash_unlock (void) {
while (FLASH->SR & FLASH_SR_BSY1);
if (FLASH->CR & FLASH_CR_LOCK) {
@ -363,13 +475,10 @@ void hw_flash_program (uint32_t offset, hw_flash_t value) {
FLASH->CR &= ~(FLASH_CR_PG);
}
hw_flash_t hw_flash_read (uint32_t offset) {
return *(uint64_t *) (FLASH_BASE + offset);
}
void hw_reset (loader_parameters_t *parameters) {
if (parameters != NULL) {
RCC->APBENR1 |= RCC_APBENR1_PWREN | RCC_APBENR1_RTCAPBEN;
RCC->APBENR1 |= (RCC_APBENR1_PWREN | RCC_APBENR1_RTCAPBEN);
PWR->CR1 |= PWR_CR1_DBP;
TAMP->BKP0R = parameters->magic;
TAMP->BKP1R = parameters->flags;
@ -382,8 +491,9 @@ void hw_reset (loader_parameters_t *parameters) {
NVIC_SystemReset();
}
void hw_loader_get_parameters (loader_parameters_t *parameters) {
RCC->APBENR1 |= RCC_APBENR1_PWREN | RCC_APBENR1_RTCAPBEN;
RCC->APBENR1 |= (RCC_APBENR1_PWREN | RCC_APBENR1_RTCAPBEN);
parameters->magic = TAMP->BKP0R;
parameters->flags = TAMP->BKP1R;
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);
}
static void hw_init_mcu (void) {
FLASH->ACR |= (FLASH_ACR_PRFTEN | (2 << FLASH_ACR_LATENCY_Pos));
while ((FLASH->ACR & FLASH_ACR_LATENCY_Msk) != (2 << FLASH_ACR_LATENCY_Pos));
RCC->PLLCFGR = (
((2 - 1) << RCC_PLLCFGR_PLLR_Pos)
| RCC_PLLCFGR_PLLREN
| (16 << RCC_PLLCFGR_PLLN_Pos)
| ((2 - 1) << RCC_PLLCFGR_PLLM_Pos)
| RCC_PLLCFGR_PLLSRC_HSI
);
#define ADC_VREF_CAL_POINT (3000)
#define ADC_VREF_CAL_VALUE (*(uint16_t *) (0x1FFF75AAUL))
RCC->CR |= RCC_CR_PLLON;
while ((RCC->CR & RCC_CR_PLLRDY_Msk) != RCC_CR_PLLRDY);
#define TEMP_CAL_POINT_1 (30)
#define TEMP_CAL_VALUE_1 (*(uint16_t *) (0x1FFF75A8UL))
RCC->CFGR = RCC_CFGR_SW_1;
while ((RCC->CFGR & RCC_CFGR_SWS_Msk) != RCC_CFGR_SWS_1);
#define TEMP_CAL_POINT_2 (130)
#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);
SysTick->VAL = 0;
SysTick->CTRL = (SysTick_CTRL_CLKSOURCE_Msk | SysTick_CTRL_ENABLE_Msk);
#define TEMP_SCALE (10)
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);
}
static void hw_init_spi (void) {
RCC->AHBENR |= RCC_AHBENR_DMA1EN;
RCC->APBENR2 |= RCC_APBENR2_SPI1EN;
DMAMUX1_Channel0->CCR = (16 << DMAMUX_CxCR_DMAREQ_ID_Pos);
DMAMUX1_Channel1->CCR = (17 << DMAMUX_CxCR_DMAREQ_ID_Pos);
DMA1_Channel1->CPAR = (uint32_t) (&SPI1->DR);
DMA1_Channel2->CPAR = (uint32_t) (&SPI1->DR);
SPI1->CR2 = (
SPI_CR2_FRXTH |
(8 - 1) << SPI_CR2_DS_Pos |
SPI_CR2_TXDMAEN |
SPI_CR2_RXDMAEN
);
SPI1->CR1 = (
SPI_CR1_SSM |
SPI_CR1_SSI |
SPI_CR1_BR_1 |
SPI_CR1_SPE |
SPI_CR1_MSTR |
SPI_CR1_CPHA
);
hw_gpio_init(GPIO_ID_SPI_CS, GPIO_OUTPUT, GPIO_PP, GPIO_SPEED_HIGH, GPIO_PULL_NONE, GPIO_AF_0, 1);
hw_gpio_init(GPIO_ID_SPI_CLK, GPIO_ALT, GPIO_PP, GPIO_SPEED_HIGH, GPIO_PULL_NONE, GPIO_AF_0, 0);
hw_gpio_init(GPIO_ID_SPI_MISO, GPIO_ALT, GPIO_PP, GPIO_SPEED_HIGH, GPIO_PULL_DOWN, GPIO_AF_0, 0);
hw_gpio_init(GPIO_ID_SPI_MOSI, GPIO_ALT, GPIO_PP, GPIO_SPEED_HIGH, GPIO_PULL_NONE, GPIO_AF_0, 0);
}
static void hw_init_i2c (void) {
RCC->APBENR1 |= RCC_APBENR1_I2C1EN;
I2C1->TIMINGR = 0x80821B20UL;
I2C1->CR1 |= (I2C_CR1_TCIE | I2C_CR1_STOPIE | I2C_CR1_RXIE | I2C_CR1_TXIE | I2C_CR1_PE);
hw_gpio_init(GPIO_ID_I2C_SCL, GPIO_ALT, GPIO_OD, GPIO_SPEED_VLOW, GPIO_PULL_NONE, GPIO_AF_6, 0);
hw_gpio_init(GPIO_ID_I2C_SDA, GPIO_ALT, GPIO_OD, GPIO_SPEED_VLOW, GPIO_PULL_NONE, GPIO_AF_6, 0);
}
static void hw_init_uart (void) {
RCC->APBENR2 |= (RCC_APBENR2_USART1EN | RCC_APBENR2_SYSCFGEN);
SYSCFG->CFGR1 |= (SYSCFG_CFGR1_PA12_RMP | SYSCFG_CFGR1_PA11_RMP);
hw_gpio_init(GPIO_ID_UART_TX, GPIO_ALT, GPIO_PP, GPIO_SPEED_LOW, GPIO_PULL_UP, GPIO_AF_1, 0);
hw_gpio_init(GPIO_ID_UART_RX, GPIO_ALT, GPIO_PP, GPIO_SPEED_LOW, GPIO_PULL_UP, GPIO_AF_1, 0);
USART1->BRR = (64000000UL) / UART_BAUD;
USART1->RQR = USART_RQR_TXFRQ | USART_RQR_RXFRQ;
USART1->CR1 = USART_CR1_FIFOEN | USART_CR1_M0 | USART_CR1_PCE | USART_CR1_TE | USART_CR1_RE | USART_CR1_UE;
}
static void hw_init_tim (void) {
RCC->APBENR1 |= (
RCC_APBENR1_DBGEN |
RCC_APBENR1_TIM3EN
);
RCC->APBENR2 |= (
RCC_APBENR2_TIM17EN |
RCC_APBENR2_TIM16EN |
RCC_APBENR2_TIM14EN |
RCC_APBENR2_USART1EN |
RCC_APBENR2_TIM1EN
);
DBG->APBFZ1 |= DBG_APB_FZ1_DBG_TIM3_STOP;
DBG->APBFZ2 |= (
DBG_APB_FZ2_DBG_TIM17_STOP |
DBG_APB_FZ2_DBG_TIM16_STOP |
DBG_APB_FZ2_DBG_TIM14_STOP |
DBG_APB_FZ2_DBG_TIM1_STOP
);
}
static void hw_init_crc (void) {
RCC->AHBENR |= RCC_AHBENR_CRCEN;
CRC->CR = (CRC_CR_REV_OUT | CRC_CR_REV_IN_0);
}
static void hw_init_misc (void) {
hw_gpio_init(GPIO_ID_N64_RESET, GPIO_INPUT, GPIO_PP, GPIO_SPEED_VLOW, GPIO_PULL_DOWN, GPIO_AF_0, 0);
hw_gpio_init(GPIO_ID_N64_CIC_CLK, GPIO_INPUT, GPIO_PP, GPIO_SPEED_VLOW, GPIO_PULL_UP, GPIO_AF_0, 0);
static void hw_misc_init (void) {
hw_gpio_init(GPIO_ID_N64_RESET, GPIO_INPUT, GPIO_OD, GPIO_SPEED_VLOW, GPIO_PULL_DOWN, GPIO_AF_0, 0);
hw_gpio_init(GPIO_ID_N64_CIC_CLK, GPIO_INPUT, GPIO_OD, GPIO_SPEED_VLOW, GPIO_PULL_UP, GPIO_AF_0, 0);
hw_gpio_init(GPIO_ID_N64_CIC_DQ, GPIO_INPUT, GPIO_OD, GPIO_SPEED_VLOW, GPIO_PULL_UP, GPIO_AF_0, 1);
hw_gpio_init(GPIO_ID_FPGA_INT, GPIO_INPUT, GPIO_PP, GPIO_SPEED_VLOW, GPIO_PULL_UP, GPIO_AF_0, 0);
hw_gpio_init(GPIO_ID_RTC_MFP, GPIO_INPUT, GPIO_PP, GPIO_SPEED_VLOW, GPIO_PULL_UP, GPIO_AF_0, 0);
hw_gpio_init(GPIO_ID_FPGA_INT, GPIO_INPUT, GPIO_OD, GPIO_SPEED_VLOW, GPIO_PULL_UP, GPIO_AF_0, 0);
hw_gpio_init(GPIO_ID_RTC_MFP, GPIO_INPUT, GPIO_OD, GPIO_SPEED_VLOW, GPIO_PULL_UP, GPIO_AF_0, 0);
}
void hw_set_vector_table (uint32_t offset) {
SCB->VTOR = (__IOM uint32_t) (offset);
}
void hw_init (void) {
hw_init_mcu();
hw_init_spi();
hw_init_i2c();
hw_init_uart();
hw_init_tim();
hw_init_crc();
hw_init_misc();
NVIC_SetPriority(EXTI0_1_IRQn, 0);
NVIC_SetPriority(EXTI2_3_IRQn, 0);
NVIC_SetPriority(EXTI4_15_IRQn, 0);
NVIC_SetPriority(I2C1_IRQn, 0);
NVIC_SetPriority(TIM14_IRQn, 0);
NVIC_SetPriority(TIM16_IRQn, 0);
NVIC_SetPriority(TIM17_IRQn, 0);
NVIC_SetPriority(TIM3_IRQn, 0);
NVIC_SetPriority(TIM1_BRK_UP_TRG_COM_IRQn, 0);
NVIC_EnableIRQ(EXTI0_1_IRQn);
NVIC_EnableIRQ(EXTI2_3_IRQn);
NVIC_EnableIRQ(EXTI4_15_IRQn);
NVIC_EnableIRQ(I2C1_IRQn);
NVIC_EnableIRQ(TIM14_IRQn);
NVIC_EnableIRQ(TIM16_IRQn);
NVIC_EnableIRQ(TIM17_IRQn);
NVIC_EnableIRQ(TIM3_IRQn);
NVIC_EnableIRQ(TIM1_BRK_UP_TRG_COM_IRQn);
void hw_primer_init (void) {
hw_clock_init();
hw_timeout_init();
hw_delay_init();
hw_led_init();
hw_uart_init();
hw_spi_init();
hw_i2c_init();
hw_crc32_init();
}
void hw_loader_init (void) {
hw_init_mcu();
hw_init_spi();
hw_clock_init();
hw_timeout_init();
hw_delay_init();
hw_led_init();
hw_spi_init();
}
void hw_primer_init (void) {
hw_init_mcu();
hw_init_spi();
hw_init_i2c();
hw_init_uart();
hw_init_crc();
}
void EXTI0_1_IRQHandler (void) {
for (int i = 0; i <= 1; i++) {
if (EXTI->FPR1 & (EXTI_FPR1_FPIF0 << i)) {
EXTI->FPR1 = (EXTI_FPR1_FPIF0 << i);
if (gpio_irq_callbacks[i].falling) {
gpio_irq_callbacks[i].falling();
}
}
if (EXTI->RPR1 & (EXTI_RPR1_RPIF0 << i)) {
EXTI->RPR1 = (EXTI_RPR1_RPIF0 << i);
if (gpio_irq_callbacks[i].rising) {
gpio_irq_callbacks[i].rising();
}
}
}
}
void EXTI2_3_IRQHandler (void) {
for (int i = 2; i <= 3; i++) {
if (EXTI->FPR1 & (EXTI_FPR1_FPIF0 << i)) {
EXTI->FPR1 = (EXTI_FPR1_FPIF0 << i);
if (gpio_irq_callbacks[i].falling) {
gpio_irq_callbacks[i].falling();
}
}
if (EXTI->RPR1 & (EXTI_RPR1_RPIF0 << i)) {
EXTI->RPR1 = (EXTI_RPR1_RPIF0 << i);
if (gpio_irq_callbacks[i].rising) {
gpio_irq_callbacks[i].rising();
}
}
}
}
void EXTI4_15_IRQHandler (void) {
for (int i = 4; i <= 15; i++) {
if (EXTI->FPR1 & (EXTI_FPR1_FPIF0 << i)) {
EXTI->FPR1 = (EXTI_FPR1_FPIF0 << i);
if (gpio_irq_callbacks[i].falling) {
gpio_irq_callbacks[i].falling();
}
}
if (EXTI->RPR1 & (EXTI_RPR1_RPIF0 << i)) {
EXTI->RPR1 = (EXTI_RPR1_RPIF0 << i);
if (gpio_irq_callbacks[i].rising) {
gpio_irq_callbacks[i].rising();
}
}
}
}
void I2C1_IRQHandler (void) {
if (I2C1->ISR & I2C_ISR_TXIS) {
I2C1->TXDR = *i2c_data_txptr++;
}
if (I2C1->ISR & I2C_ISR_RXNE) {
*i2c_data_rxptr++ = I2C1->RXDR;
}
if (I2C1->ISR & I2C_ISR_TC) {
I2C1->CR2 = i2c_next_cr2;
}
if (I2C1->ISR & I2C_ISR_STOPF) {
I2C1->ICR = I2C_ICR_STOPCF;
if (i2c_callback) {
i2c_callback();
i2c_callback = 0;
}
}
}
void TIM14_IRQHandler (void) {
TIM14->SR &= ~(TIM_SR_UIF);
if (tim_callbacks[0]) {
tim_callbacks[0]();
tim_callbacks[0] = 0;
}
}
void TIM16_IRQHandler (void) {
TIM16->SR &= ~(TIM_SR_UIF);
if (tim_callbacks[1]) {
tim_callbacks[1]();
tim_callbacks[1] = 0;
}
}
void TIM17_IRQHandler (void) {
TIM17->SR &= ~(TIM_SR_UIF);
if (tim_callbacks[2]) {
tim_callbacks[2]();
tim_callbacks[2] = 0;
}
}
void TIM3_IRQHandler (void) {
TIM3->SR &= ~(TIM_SR_UIF);
if (tim_callbacks[3]) {
tim_callbacks[3]();
tim_callbacks[3] = 0;
}
}
void TIM1_BRK_UP_TRG_COM_IRQHandler (void) {
TIM1->SR &= ~(TIM_SR_UIF);
if (tim_callbacks[4]) {
tim_callbacks[4]();
tim_callbacks[4] = 0;
}
void hw_app_init (void) {
hw_clock_init();
hw_timeout_init();
hw_delay_init();
hw_adc_init();
hw_led_init();
hw_misc_init();
hw_uart_init();
hw_spi_init();
hw_i2c_init();
hw_crc32_init();
}

View File

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

View File

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

View File

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

View File

@ -114,27 +114,33 @@ static void lcmxo2_write_data (uint8_t *buffer, uint32_t length) {
static void lcmxo2_reset_bus (void) {
#ifdef LCMXO2_I2C
uint8_t reset_data = 0;
hw_i2c_raw(LCMXO2_I2C_ADDR_RESET, &reset_data, sizeof(reset_data), NULL, 0);
hw_i2c_trx(LCMXO2_I2C_ADDR_RESET, &reset_data, sizeof(reset_data), NULL, 0);
#else
lcmxo2_reg_set(LCMXO2_CFGCR, CFGCR_RSTE);
lcmxo2_reg_set(LCMXO2_CFGCR, 0);
#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
uint8_t packet[20] = { cmd, ((arg >> 16) & 0xFF), ((arg >> 8) & 0xFF), (arg & 0xFF) };
int packet_length = ((type == CMD_TWO_OP) ? 3 : 4);
if (write) {
for (int i = 0; i < length; i++) {
packet[packet_length + i] = buffer[i];
}
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
uint32_t data = (cmd << 24) | (arg & 0x00FFFFFF);
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_SCR,
(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_START
);
while (fpga_reg_get(REG_VENDOR_SCR) & VENDOR_SCR_BUSY);
if (length > 0) {
if (write) {
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_reg_set(LCMXO2_CFGCR, 0);
return false;
#endif
}
static void lcmxo2_read_device_id (uint8_t *id) {
lcmxo2_execute_cmd(IDCODE_PUB, 0, CMD_NORMAL, id, DEVICE_ID_SIZE, false);
static bool lcmxo2_read_device_id (uint8_t *id) {
return lcmxo2_execute_cmd(IDCODE_PUB, 0, CMD_NORMAL, id, DEVICE_ID_SIZE, false);
}
static uint32_t lcmxo2_read_status (void) {
uint32_t status = 0;
lcmxo2_execute_cmd(LSC_READ_STATUS, 0, CMD_NORMAL, (uint8_t *) (&status), 4, false);
return SWAP32(status);
static uint32_t lcmxo2_read_status (uint32_t *status) {
uint32_t tmp = 0;
bool error = lcmxo2_execute_cmd(LSC_READ_STATUS, 0, CMD_NORMAL, (uint8_t *) (&tmp), 4, false);
*status = SWAP32(tmp);
return error;
}
static bool lcmxo2_wait_busy (void) {
bool error;
uint32_t status;
do {
status = lcmxo2_read_status();
} while(status & LSC_STATUS_BUSY);
return (status & LSC_STATUS_FAIL);
error = lcmxo2_read_status(&status);
} while ((!error) && (status & LSC_STATUS_BUSY));
return (error) || (status & LSC_STATUS_FAIL);
}
static bool lcmxo2_enable_flash (void) {
#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
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
return lcmxo2_wait_busy();
}
static void lcmxo2_disable_flash (void) {
lcmxo2_wait_busy();
lcmxo2_execute_cmd(ISC_DISABLE, 0, CMD_TWO_OP, NULL, 0, false);
lcmxo2_execute_cmd(ISC_NOOP, 0xFFFFFF, CMD_NORMAL, NULL, 0, false);
static bool lcmxo2_disable_flash (void) {
if (lcmxo2_wait_busy()) {
return true;
}
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) {
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();
}
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();
}
static void lcmxo2_reset_flash_address (void) {
lcmxo2_execute_cmd(LSC_INIT_ADDRESS, 0, CMD_NORMAL, NULL, 0, false);
static bool lcmxo2_reset_flash_address (void) {
return lcmxo2_execute_cmd(LSC_INIT_ADDRESS, 0, CMD_NORMAL, NULL, 0, false);
}
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();
}
static void lcmxo2_read_flash_page (uint8_t *buffer) {
lcmxo2_execute_cmd(LSC_READ_INCR_NV, 1, CMD_DELAYED, buffer, FLASH_PAGE_SIZE, false);
static bool lcmxo2_read_flash_page (uint8_t *buffer) {
return lcmxo2_execute_cmd(LSC_READ_INCR_NV, 1, CMD_DELAYED, buffer, FLASH_PAGE_SIZE, false);
}
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();
}
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();
}
static void lcmxo2_read_featbits (uint8_t *buffer) {
lcmxo2_execute_cmd(LSC_READ_FEABITS, 0, CMD_NORMAL, buffer, FEATBITS_SIZE, false);
static bool lcmxo2_read_featbits (uint8_t *buffer) {
return lcmxo2_execute_cmd(LSC_READ_FEABITS, 0, CMD_NORMAL, buffer, FEATBITS_SIZE, false);
}
static void lcmxo2_refresh (void) {
lcmxo2_execute_cmd(LSC_REFRESH, 0, CMD_TWO_OP, NULL, 0, false);
static bool lcmxo2_refresh (void) {
return lcmxo2_execute_cmd(LSC_REFRESH, 0, CMD_TWO_OP, NULL, 0, false);
}
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) {
uint8_t programmed[2] = { 0x00, 0x00 };
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])) {
return false;
}
if (lcmxo2_erase_featbits()) {
return true;
}
if (lcmxo2_write_featbits(target)) {
return true;
}
lcmxo2_read_featbits(programmed);
if (lcmxo2_read_featbits(programmed)) {
return true;
}
if ((programmed[0] != target[0]) || (programmed[1] != target[1])) {
return true;
}
return false;
}
@ -403,7 +443,7 @@ void vendor_initial_configuration (vendor_get_cmd_t get_cmd, vendor_send_respons
break;
case CMD_GET_DEVICE_ID:
lcmxo2_read_device_id(buffer);
error = lcmxo2_read_device_id(buffer);
tx_length = 4;
break;
@ -416,7 +456,7 @@ void vendor_initial_configuration (vendor_get_cmd_t get_cmd, vendor_send_respons
break;
case CMD_RESET_ADDRESS:
lcmxo2_reset_flash_address();
error = lcmxo2_reset_flash_address();
break;
case CMD_WRITE_PAGE:
@ -424,7 +464,7 @@ void vendor_initial_configuration (vendor_get_cmd_t get_cmd, vendor_send_respons
break;
case CMD_READ_PAGE:
lcmxo2_read_flash_page(buffer);
error = lcmxo2_read_flash_page(buffer);
tx_length = FLASH_PAGE_SIZE;
break;
@ -437,7 +477,7 @@ void vendor_initial_configuration (vendor_get_cmd_t get_cmd, vendor_send_respons
break;
case CMD_REFRESH:
lcmxo2_refresh();
error = lcmxo2_refresh();
hw_delay_ms(200);
break;

View File

@ -2,102 +2,46 @@
#include "hw.h"
#include "led.h"
#include "rtc.h"
#include "task.h"
#include "timer.h"
#define LED_MS_PER_TICK (10)
#define LED_ERROR_TICKS_PERIOD (50)
#define LED_ERROR_TICKS_ON (25)
#define LED_ACT_TICKS_PERIOD (15)
#define LED_ACT_TICKS_ON (6)
#define LED_REFRESH_PERIOD_MS (50)
#define LED_PULSE_LENGTH_MS (200)
#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 uint32_t error_timer = 0;
static volatile bool cic_error = false;
static volatile bool rtc_error = false;
static bool activity_pulse = false;
static int activity_pulse_timer = 0;
static uint32_t act_timer = 0;
static uint32_t current_act_counter = 0;
static volatile uint32_t next_act_counter = 0;
static bool cic_error = false;
static bool rtc_error = false;
static bool error_active = false;
static int error_timer = 0;
static void led_task_resume (void) {
task_set_ready(TASK_ID_LED);
}
static void led_set_state (bool state, bool force) {
void led_activity_on (void) {
rtc_settings_t *settings = rtc_get_settings();
if (settings->led_enabled || force) {
if (state) {
if (!activity_pulse && !error_active && settings->led_enabled) {
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);
}
}
static void led_update_error_mode (void) {
if (error_mode) {
if (!(cic_error || rtc_error)) {
led_set_state(false, true);
error_mode = false;
act_timer = 0;
}
} else {
if (cic_error || rtc_error) {
led_set_state(false, true);
error_mode = true;
error_timer = 0;
}
}
}
static void led_process_errors (void) {
if (error_timer == 0) {
error_timer = LED_ERROR_TICKS_PERIOD;
if (cic_error) {
error_timer *= 1;
} else if (rtc_error) {
error_timer *= 2;
}
error_timer += LED_ERROR_TICKS_PERIOD;
}
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);
}
}
void led_activity_pulse (void) {
activity_pulse = true;
activity_pulse_timer = LED_PULSE_LENGTH_MS;
}
@ -106,10 +50,16 @@ void led_blink_error (led_error_t error) {
case LED_ERROR_CIC:
cic_error = true;
break;
case LED_ERROR_RTC:
rtc_error = true;
break;
}
error_active = (
cic_error |
rtc_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:
cic_error = false;
break;
case LED_ERROR_RTC:
rtc_error = false;
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) {
hw_tim_setup(TIM_ID_LED, LED_MS_PER_TICK, led_task_resume);
void led_process (void) {
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) {
led_process_errors();
if (error_active) {
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 {
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;
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_clear_error (led_error_t error);
void led_blink_act (void);
void led_task (void);
void led_init (void);
void led_process (void);
#endif

View File

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

View File

@ -19,7 +19,7 @@ static uint8_t primer_get_command (uint8_t *buffer, uint8_t *rx_length) {
uint32_t received_crc32;
uint8_t token[4];
while (1) {
while (true) {
hw_crc32_reset();
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) {
hw_primer_init();
vendor_initial_configuration(primer_get_command, primer_send_response);
hw_uart_wait_busy();
hw_uart_write_wait_busy();
hw_reset(NULL);
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -29,9 +29,12 @@ typedef struct usb_tx_info {
void usb_create_packet (usb_tx_info_t *info, usb_packet_cmd_e cmd);
bool usb_enqueue_packet (usb_tx_info_t *info);
bool usb_prepare_read (uint32_t *args);
void usb_get_read_info (uint32_t *args);
void usb_init (void);
void usb_process (void);

View File

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

View File

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

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"
panic-message = "0.3.0"
rust-ini = "0.18.0"
serial2 = "0.1.7"
serialport = "4.2.0"
serial2 = "0.2.17"
serialport = "4.3.0"
[profile.release]
lto = true

View File

@ -166,6 +166,20 @@ const MAX_PACKET_LENGTH: usize = 8 * 1024 * 1024;
const SUPPORTED_USB_PROTOCOL_VERSION: u16 = 2;
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) {
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> {
if path.len() == 0 {
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 debug_handler = debug::new();
let mut debug_handler = debug::Handler::new();
println!(
"{}\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> {
let mut sc64 = init_sc64(connection, true)?;
let mut debug_handler = debug::new();
let mut debug_handler = debug::Handler::new();
if args.euc_jp {
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!(" IS-Viewer 64 offset: 0x{:08X}", state.isv_address);
println!(" FPGA debug data: {}", state.fpga_debug_data);
println!(" MCU stack usage: {}", state.mcu_stack_usage);
println!(" Diagnostic data: {}", state.diagnostic_data);
Ok(())
}
@ -859,7 +859,7 @@ fn handle_server_command(connection: Connection, args: &ServerArgs) -> Result<()
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) => {
println!(
"{}: 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> {
let mut sc64 = match connection {
Connection::Local(port) => sc64::new_local(port),
Connection::Remote(remote) => sc64::new_remote(remote),
Connection::Local(port) => sc64::SC64::open_local(port),
Connection::Remote(remote) => sc64::SC64::open_remote(remote),
}?;
if check_firmware {

View File

@ -2,7 +2,7 @@ mod cic;
mod error;
pub mod firmware;
mod link;
mod server;
pub mod server;
mod time;
mod types;
@ -12,7 +12,7 @@ pub use self::{
server::ServerEvent,
types::{
BootMode, ButtonMode, ButtonState, CicSeed, DataPacket, DdDiskState, DdDriveType, DdMode,
DebugPacket, DiskPacket, DiskPacketKind, FpgaDebugData, McuStackUsage, SaveType,
DebugPacket, DiagnosticData, DiskPacket, DiskPacketKind, FpgaDebugData, SaveType,
SaveWriteback, Switch, TvType,
},
};
@ -55,7 +55,7 @@ pub struct DeviceState {
pub led_enable: Switch,
pub datetime: DateTime<Local>,
pub fpga_debug_data: FpgaDebugData,
pub mcu_stack_usage: McuStackUsage,
pub diagnostic_data: DiagnosticData,
}
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()?)
}
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 {
id: b'?',
args: [0, 0],
@ -359,7 +359,7 @@ impl SC64 {
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 {
id: b'%',
args: [0, 0],
@ -557,8 +557,8 @@ impl SC64 {
rom_extended_enable: get_config!(self, RomExtendedEnable)?,
led_enable: get_setting!(self, LedEnable)?,
datetime: self.get_datetime()?,
fpga_debug_data: self.command_debug_get()?,
mcu_stack_usage: self.command_stack_usage_get()?,
fpga_debug_data: self.command_fpga_debug_data_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 {
port
} else {
@ -800,23 +801,11 @@ pub fn new_local(port: Option<String>) -> Result<SC64, Error> {
Ok(sc64)
}
pub fn new_remote(address: String) -> Result<SC64, Error> {
pub fn open_remote(address: String) -> Result<Self, Error> {
let mut sc64 = SC64 {
link: link::new_remote(&address)?,
};
sc64.check_device()?;
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::{
error::Error,
link::{new_serial, Command, DataType, Packet, Response, Serial},
link::{list_local_devices, new_serial, Command, DataType, Packet, Response, Serial},
};
use std::{
collections::VecDeque,
@ -22,11 +22,16 @@ pub enum ServerEvent {
Err(String),
}
pub fn run_server(
port: &str,
pub fn run(
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()
};
let listener = TcpListener::bind(address)?;
let listening_address = listener.local_addr()?;
event_callback(ServerEvent::Listening(listening_address.to_string()));
@ -36,7 +41,7 @@ pub fn run_server(
Ok(mut stream) => {
let peer = stream.peer_addr()?.to_string();
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())),
Err(error) => event_callback(ServerEvent::Err(error.to_string())),
}
@ -58,14 +63,14 @@ enum Event {
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 exit_flag = Arc::new(AtomicBool::new(false));
let mut stream_writer = BufWriter::new(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_reader = serial.clone();

View File

@ -828,38 +828,82 @@ impl Display for FpgaDebugData {
}
}
pub struct McuStackUsage {
pub struct DiagnosticDataV0 {
pub cic: u32,
pub rtc: u32,
pub led: 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;
fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> {
if value.len() != 16 {
return Err(Error::new("Invalid data length for MCU stack usage"));
if value.len() < 4 {
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()),
rtc: u32::from_be_bytes(value[4..8].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()),
})
}));
}
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 {
if self.cic > 0 {
f.write_fmt(format_args!("CIC: {}, ", self.cic))?;
match self {
DiagnosticData::V0(d) => {
if d.cic > 0 {
f.write_fmt(format_args!("CIC: {}, ", d.cic))?;
}
f.write_fmt(format_args!(
"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 {
@ -874,7 +918,7 @@ macro_rules! get_config {
macro_rules! get_setting {
($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)]
if let Setting::$setting(value) = $sc64.command_setting_get(SettingId::$setting)? {
Ok(value)

View File

@ -204,9 +204,16 @@ class STM32Bootloader:
__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.__read = read
self.__flush = flush
self.__progress = progress
def __append_xor(self, data: bytes) -> bytes:
@ -217,7 +224,7 @@ class STM32Bootloader:
def __check_ack(self) -> None:
response = self.__read(1)
if (response == None):
if (len(response) != 1):
raise STM32BootloaderException('No ACK/NACK byte received')
if (response == self.__NACK):
raise STM32BootloaderException('NACK byte received')
@ -228,18 +235,22 @@ class STM32Bootloader:
if (len(cmd) != 1):
raise ValueError('Command must contain only one byte')
self.__write(self.__append_xor(cmd))
self.__flush()
self.__check_ack()
def __data_write(self, data: bytes) -> None:
self.__write(self.__append_xor(data))
self.__flush()
self.__check_ack()
def __data_read(self) -> bytes:
length = self.__read(1)
if (len(length) != 1):
raise STM32BootloaderException('Did not receive length byte')
length = length[0]
data = self.__read(length + 1)
length = (length[0] + 1)
data = self.__read(length)
if (len(data) != length):
raise STM32BootloaderException('Did not receive requested data bytes')
self.__check_ack()
return data
@ -253,7 +264,10 @@ class STM32Bootloader:
self.__cmd_send(b'\x11')
self.__data_write(address.to_bytes(4, byteorder='big'))
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:
self.__cmd_send(b'\x21')
@ -288,8 +302,12 @@ class STM32Bootloader:
def connect(self, id: int) -> None:
if (not self.__connected):
try:
self.__write(self.__INIT)
self.__flush()
self.__check_ack()
except STM32BootloaderException as e:
raise STM32BootloaderException(f'Could not connect to the STM32 ({e})')
self.__connected = True
dev_id = self.__get_id()
if (dev_id != id):
@ -339,9 +357,16 @@ class LCMXO2Primer:
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.__read = read
self.__flush = flush
self.__progress = progress
def __cmd_execute(self, cmd: bytes, data: bytes=b'') -> bytes:
@ -355,14 +380,20 @@ class LCMXO2Primer:
packet += data
packet += crc32(packet).to_bytes(4, byteorder='little')
self.__write(packet)
self.__flush()
response = self.__read(5)
if (len(response) != 5):
raise LCMXO2PrimerException(f'No response received [{cmd}]')
length = int.from_bytes(response[4:5], byteorder='little')
response += self.__read(length)
calculated_checksum = crc32(response)
received_checksum = int.from_bytes(self.__read(4), byteorder='little')
response_data = self.__read(length)
if (len(response_data) != length):
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'):
raise LCMXO2PrimerException(f'Invalid response token [{response[0:3]} / {cmd}]')
@ -371,9 +402,10 @@ class LCMXO2Primer:
if (calculated_checksum != received_checksum):
raise LCMXO2PrimerException(f'Invalid response checksum [{cmd}]')
return response[5:]
return response_data
def connect(self, id: bytes) -> None:
try:
primer_id = self.__cmd_execute(self.__CMD_GET_PRIMER_ID)
if (primer_id != self.__PRIMER_ID_LCMXO2):
raise LCMXO2PrimerException('Invalid primer ID received')
@ -381,6 +413,8 @@ class LCMXO2Primer:
dev_id = self.__cmd_execute(self.__CMD_GET_DEVICE_ID)
if (dev_id != id):
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:
erase_description = f'{description} / Erase'
@ -599,8 +633,8 @@ class SC64BringUp:
write_timeout=self.__SERIAL_TIMEOUT
)
stm32_bootloader = STM32Bootloader(link.write, link.read, self.__progress)
lcmxo2_primer = LCMXO2Primer(link.write, link.read, self.__progress)
stm32_bootloader = STM32Bootloader(link.write, link.read, link.flush, self.__progress)
lcmxo2_primer = LCMXO2Primer(link.write, link.read, link.flush, self.__progress)
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')
@ -645,7 +679,7 @@ if __name__ == '__main__':
sc64_bring_up = SC64BringUp(progress=utils.progress)
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(f'Serial port: {port}')
@ -683,6 +717,7 @@ if __name__ == '__main__':
original_sigint_handler = signal.getsignal(signal.SIGINT)
try:
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)
except (serial.SerialException, STM32BootloaderException, LCMXO2PrimerException, SC64Exception) as e:
if (utils.get_progress_active):