mirror of
https://github.com/Polprzewodnikowy/SummerCart64.git
synced 2024-11-21 21:49:15 +01:00
[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:
parent
be37025d42
commit
421d0438f3
2
build.sh
2
build.sh
@ -83,6 +83,8 @@ build_cic () {
|
|||||||
build_fpga () {
|
build_fpga () {
|
||||||
if [ "$BUILT_FPGA" = true ]; then return; fi
|
if [ "$BUILT_FPGA" = true ]; then return; fi
|
||||||
|
|
||||||
|
build_cic
|
||||||
|
|
||||||
pushd fw/project/lcmxo2 > /dev/null
|
pushd fw/project/lcmxo2 > /dev/null
|
||||||
if [ "$FORCE_CLEAN" = true ]; then
|
if [ "$FORCE_CLEAN" = true ]; then
|
||||||
rm -rf ./impl1/
|
rm -rf ./impl1/
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
BUILDER_IMAGE="ghcr.io/polprzewodnikowy/sc64env:v1.8"
|
BUILDER_IMAGE="ghcr.io/polprzewodnikowy/sc64env:v1.9"
|
||||||
|
|
||||||
pushd $(dirname $0) > /dev/null
|
pushd $(dirname $0) > /dev/null
|
||||||
|
|
||||||
|
@ -4,27 +4,28 @@
|
|||||||
|
|
||||||
## N64 commands
|
## N64 commands
|
||||||
|
|
||||||
| id | name | arg0 | arg1 | rsp0 | rsp1 | description |
|
| id | name | arg0 | arg1 | rsp0 | rsp1 | description |
|
||||||
| --- | --------------------- | -------------- | ------------ | ---------------- | -------------- | ---------------------------------------------------------- |
|
| --- | --------------------- | ------------- | ------------ | ---------------- | -------------- | ---------------------------------------------------------- |
|
||||||
| `v` | **IDENTIFIER_GET** | --- | --- | identifier | --- | Get flashcart identifier `SCv2` |
|
| `v` | **IDENTIFIER_GET** | --- | --- | identifier | --- | Get flashcart identifier `SCv2` |
|
||||||
| `V` | **VERSION_GET** | --- | --- | major/minor | revision | Get flashcart firmware version |
|
| `V` | **VERSION_GET** | --- | --- | major/minor | revision | Get flashcart firmware version |
|
||||||
| `c` | **CONFIG_GET** | config_id | --- | --- | current_value | Get config option |
|
| `c` | **CONFIG_GET** | config_id | --- | --- | current_value | Get config option |
|
||||||
| `C` | **CONFIG_SET** | config_id | new_value | --- | previous_value | Set config option and get previous value |
|
| `C` | **CONFIG_SET** | config_id | new_value | --- | previous_value | Set config option and get previous value |
|
||||||
| `a` | **SETTING_GET** | setting_id | --- | --- | current_value | Get persistent setting option |
|
| `a` | **SETTING_GET** | setting_id | --- | --- | current_value | Get persistent setting option |
|
||||||
| `A` | **SETTING_SET** | setting_id | new_value | --- | --- | Set persistent setting option |
|
| `A` | **SETTING_SET** | setting_id | new_value | --- | --- | Set persistent setting option |
|
||||||
| `t` | **TIME_GET** | --- | --- | time_0 | time_1 | Get current RTC value |
|
| `t` | **TIME_GET** | --- | --- | time_0 | time_1 | Get current RTC value |
|
||||||
| `T` | **TIME_SET** | time_0 | time_1 | --- | --- | Set new RTC value |
|
| `T` | **TIME_SET** | time_0 | time_1 | --- | --- | Set new RTC value |
|
||||||
| `m` | **USB_READ** | pi_address | length | --- | --- | Receive data from USB to flashcart |
|
| `m` | **USB_READ** | pi_address | length | --- | --- | Receive data from USB to flashcart |
|
||||||
| `M` | **USB_WRITE** | pi_address | length/type | --- | --- | Send data from from flashcart to USB |
|
| `M` | **USB_WRITE** | pi_address | length/type | --- | --- | Send data from from flashcart to USB |
|
||||||
| `u` | **USB_READ_STATUS** | --- | --- | read_status/type | length | Get USB read status and type/length |
|
| `u` | **USB_READ_STATUS** | --- | --- | read_status/type | length | Get USB read status and type/length |
|
||||||
| `U` | **USB_WRITE_STATUS** | --- | --- | write_status | --- | Get USB write status |
|
| `U` | **USB_WRITE_STATUS** | --- | --- | write_status | --- | Get USB write status |
|
||||||
| `i` | **SD_CARD_OP** | pi_address | operation | --- | return_data | Perform special operation on SD card |
|
| `i` | **SD_CARD_OP** | pi_address | operation | --- | return_data | Perform special operation on SD card |
|
||||||
| `I` | **SD_SECTOR_SET** | sector | --- | --- | --- | Set starting sector for next SD card R/W operation |
|
| `I` | **SD_SECTOR_SET** | sector | --- | --- | --- | Set starting sector for next SD card R/W operation |
|
||||||
| `s` | **SD_READ** | pi_address | sector_count | --- | --- | Read sectors from SD card to flashcart |
|
| `s` | **SD_READ** | pi_address | sector_count | --- | --- | Read sectors from SD card to flashcart |
|
||||||
| `S` | **SD_WRITE** | pi_address | sector_count | --- | --- | Write sectors from flashcart to SD card |
|
| `S` | **SD_WRITE** | pi_address | sector_count | --- | --- | Write sectors from flashcart to SD card |
|
||||||
| `D` | **DISK_MAPPING_SET** | pi_address | table_size | --- | --- | Set 64DD disk mapping for SD mode |
|
| `D` | **DISK_MAPPING_SET** | pi_address | table_size | --- | --- | Set 64DD disk mapping for SD mode |
|
||||||
| `w` | **WRITEBACK_PENDING** | --- | --- | pending_status | --- | Get save writeback status (is write queued to the SD card) |
|
| `w` | **WRITEBACK_PENDING** | --- | --- | pending_status | --- | Get save writeback status (is write queued to the SD card) |
|
||||||
| `W` | **WRITEBACK_SD_INFO** | pi_address | --- | --- | --- | Load writeback SD sector table and enable it |
|
| `W` | **WRITEBACK_SD_INFO** | pi_address | --- | --- | --- | Load writeback SD sector table and enable it |
|
||||||
| `K` | **FLASH_PROGRAM** | pi_address | length | --- | --- | Program flash with bytes loaded into data buffer |
|
| `K` | **FLASH_PROGRAM** | pi_address | length | --- | --- | Program flash with bytes loaded into data buffer |
|
||||||
| `p` | **FLASH_WAIT_BUSY** | wait | --- | erase_block_size | --- | Wait until flash ready / get block erase size |
|
| `p` | **FLASH_WAIT_BUSY** | wait | --- | erase_block_size | --- | Wait until flash ready / get block erase size |
|
||||||
| `P` | **FLASH_ERASE_BLOCK** | pi_address | --- | --- | --- | Start flash block erase |
|
| `P` | **FLASH_ERASE_BLOCK** | pi_address | --- | --- | --- | Start flash block erase |
|
||||||
|
| `%` | **DIAGNOSTIC_GET** | diagnostic_id | --- | --- | value | Get diagnostic data |
|
||||||
|
@ -170,7 +170,7 @@ Available packet IDs are listed in the [asynchronous packets](#asynchronous-pack
|
|||||||
| `f` | **FIRMWARE_BACKUP** | address | --- | --- | status/length | Backup firmware to specified memory address |
|
| `f` | **FIRMWARE_BACKUP** | address | --- | --- | status/length | Backup firmware to specified memory address |
|
||||||
| `F` | **FIRMWARE_UPDATE** | address | length | --- | status | Update firmware from specified memory address |
|
| `F` | **FIRMWARE_UPDATE** | address | length | --- | status | Update firmware from specified memory address |
|
||||||
| `?` | **DEBUG_GET** | --- | --- | --- | debug_data | Get internal FPGA debug info |
|
| `?` | **DEBUG_GET** | --- | --- | --- | debug_data | Get internal FPGA debug info |
|
||||||
| `%` | **STACK_USAGE_GET** | --- | --- | --- | stack_usage | Get per task stack usage |
|
| `%` | **DIAGNOSTIC_GET** | --- | --- | --- | diagnostic_data | Get diagnostic data |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
@ -474,7 +474,7 @@ module mcu_top (
|
|||||||
18'd0,
|
18'd0,
|
||||||
n64_scb.flashram_write_or_erase,
|
n64_scb.flashram_write_or_erase,
|
||||||
n64_scb.flashram_sector_or_all,
|
n64_scb.flashram_sector_or_all,
|
||||||
n64_scb.flashram_sector,
|
n64_scb.flashram_page,
|
||||||
n64_scb.flashram_pending,
|
n64_scb.flashram_pending,
|
||||||
1'b0
|
1'b0
|
||||||
};
|
};
|
||||||
|
@ -8,7 +8,7 @@ module n64_flashram (
|
|||||||
);
|
);
|
||||||
|
|
||||||
localparam [31:0] FLASH_TYPE_ID = 32'h1111_8001;
|
localparam [31:0] FLASH_TYPE_ID = 32'h1111_8001;
|
||||||
localparam [31:0] FLASH_MODEL_ID = 32'h00C2_001D;
|
localparam [31:0] FLASH_MODEL_ID = 32'h0032_00F1;
|
||||||
|
|
||||||
typedef enum bit [7:0] {
|
typedef enum bit [7:0] {
|
||||||
CMD_STATUS_MODE = 8'hD2,
|
CMD_STATUS_MODE = 8'hD2,
|
||||||
@ -97,14 +97,14 @@ module n64_flashram (
|
|||||||
CMD_ERASE_SECTOR: begin
|
CMD_ERASE_SECTOR: begin
|
||||||
state <= STATE_STATUS;
|
state <= STATE_STATUS;
|
||||||
erase_enabled <= 1'b1;
|
erase_enabled <= 1'b1;
|
||||||
n64_scb.flashram_sector <= reg_bus.wdata[9:0];
|
n64_scb.flashram_page <= reg_bus.wdata[9:0];
|
||||||
n64_scb.flashram_sector_or_all <= 1'b0;
|
n64_scb.flashram_sector_or_all <= 1'b0;
|
||||||
end
|
end
|
||||||
|
|
||||||
CMD_ERASE_CHIP: begin
|
CMD_ERASE_CHIP: begin
|
||||||
state <= STATE_STATUS;
|
state <= STATE_STATUS;
|
||||||
erase_enabled <= 1'b1;
|
erase_enabled <= 1'b1;
|
||||||
n64_scb.flashram_sector <= 10'd0;
|
n64_scb.flashram_page <= 10'd0;
|
||||||
n64_scb.flashram_sector_or_all <= 1'b1;
|
n64_scb.flashram_sector_or_all <= 1'b1;
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -126,7 +126,7 @@ module n64_flashram (
|
|||||||
state <= STATE_STATUS;
|
state <= STATE_STATUS;
|
||||||
status[WRITE_BUSY] <= 1'b1;
|
status[WRITE_BUSY] <= 1'b1;
|
||||||
status[WRITE_DONE] <= 1'b0;
|
status[WRITE_DONE] <= 1'b0;
|
||||||
n64_scb.flashram_sector <= reg_bus.wdata[9:0];
|
n64_scb.flashram_page <= reg_bus.wdata[9:0];
|
||||||
n64_scb.flashram_pending <= 1'b1;
|
n64_scb.flashram_pending <= 1'b1;
|
||||||
n64_scb.flashram_write_or_erase <= 1'b0;
|
n64_scb.flashram_write_or_erase <= 1'b0;
|
||||||
n64_scb.flashram_sector_or_all <= 1'b0;
|
n64_scb.flashram_sector_or_all <= 1'b0;
|
||||||
@ -134,9 +134,9 @@ module n64_flashram (
|
|||||||
endcase
|
endcase
|
||||||
end
|
end
|
||||||
end else begin
|
end else begin
|
||||||
if (reg_bus.address[1] && state != STATE_BUFFER) begin
|
if (reg_bus.address[1] && state == STATE_STATUS) begin
|
||||||
status[ERASE_BUSY] <= reg_bus.wdata[ERASE_BUSY];
|
status[ERASE_DONE] <= 1'b0;
|
||||||
status[WRITE_BUSY] <= reg_bus.wdata[WRITE_BUSY];
|
status[WRITE_DONE] <= 1'b0;
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -22,7 +22,7 @@ interface n64_scb ();
|
|||||||
|
|
||||||
logic flashram_pending;
|
logic flashram_pending;
|
||||||
logic flashram_done;
|
logic flashram_done;
|
||||||
logic [9:0] flashram_sector;
|
logic [9:0] flashram_page;
|
||||||
logic flashram_sector_or_all;
|
logic flashram_sector_or_all;
|
||||||
logic flashram_write_or_erase;
|
logic flashram_write_or_erase;
|
||||||
logic flashram_read_mode;
|
logic flashram_read_mode;
|
||||||
@ -84,7 +84,7 @@ interface n64_scb ();
|
|||||||
|
|
||||||
input flashram_pending,
|
input flashram_pending,
|
||||||
output flashram_done,
|
output flashram_done,
|
||||||
input flashram_sector,
|
input flashram_page,
|
||||||
input flashram_sector_or_all,
|
input flashram_sector_or_all,
|
||||||
input flashram_write_or_erase,
|
input flashram_write_or_erase,
|
||||||
|
|
||||||
@ -143,7 +143,7 @@ interface n64_scb ();
|
|||||||
modport flashram (
|
modport flashram (
|
||||||
output flashram_pending,
|
output flashram_pending,
|
||||||
input flashram_done,
|
input flashram_done,
|
||||||
output flashram_sector,
|
output flashram_page,
|
||||||
output flashram_sector_or_all,
|
output flashram_sector_or_all,
|
||||||
output flashram_write_or_erase,
|
output flashram_write_or_erase,
|
||||||
|
|
||||||
|
@ -59,6 +59,7 @@ module n64_si (
|
|||||||
// Data falling/rising event generator
|
// Data falling/rising event generator
|
||||||
|
|
||||||
logic last_si_dq_in;
|
logic last_si_dq_in;
|
||||||
|
logic si_dq_in_inhibit;
|
||||||
|
|
||||||
always_ff @(posedge clk) begin
|
always_ff @(posedge clk) begin
|
||||||
if (si_clk_rising_edge) begin
|
if (si_clk_rising_edge) begin
|
||||||
@ -70,14 +71,14 @@ module n64_si (
|
|||||||
logic si_dq_rising_edge;
|
logic si_dq_rising_edge;
|
||||||
|
|
||||||
always_comb begin
|
always_comb begin
|
||||||
si_dq_falling_edge = si_clk_rising_edge && last_si_dq_in && !si_dq_in;
|
si_dq_falling_edge = si_clk_rising_edge && last_si_dq_in && !si_dq_in && !si_dq_in_inhibit;
|
||||||
si_dq_rising_edge = si_clk_rising_edge && !last_si_dq_in && si_dq_in;
|
si_dq_rising_edge = si_clk_rising_edge && !last_si_dq_in && si_dq_in && !si_dq_in_inhibit;
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
// RX bit generator
|
// RX bit generator
|
||||||
|
|
||||||
logic [3:0] rx_sub_bit_counter;
|
logic [4:0] rx_sub_bit_counter;
|
||||||
logic rx_timeout;
|
logic rx_timeout;
|
||||||
logic rx_bit_valid;
|
logic rx_bit_valid;
|
||||||
logic rx_bit_data;
|
logic rx_bit_data;
|
||||||
@ -94,7 +95,7 @@ module n64_si (
|
|||||||
always_comb begin
|
always_comb begin
|
||||||
rx_timeout = si_clk_rising_edge && si_dq_in && (&rx_sub_bit_counter);
|
rx_timeout = si_clk_rising_edge && si_dq_in && (&rx_sub_bit_counter);
|
||||||
rx_bit_valid = si_dq_rising_edge;
|
rx_bit_valid = si_dq_rising_edge;
|
||||||
rx_bit_data = (rx_sub_bit_counter >= 4'd3) ? 1'b0 : 1'b1;
|
rx_bit_data = (rx_sub_bit_counter >= 5'd4) ? 1'b0 : 1'b1;
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
@ -124,7 +125,7 @@ module n64_si (
|
|||||||
logic rx_stop;
|
logic rx_stop;
|
||||||
|
|
||||||
always_comb begin
|
always_comb begin
|
||||||
rx_stop = si_clk_rising_edge && si_dq_in && (rx_sub_bit_counter == 4'd7) && (rx_bit_counter == 3'd1);
|
rx_stop = si_clk_rising_edge && si_dq_in && (rx_sub_bit_counter == 5'd15) && (rx_bit_counter == 3'd1);
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
@ -260,7 +261,8 @@ module n64_si (
|
|||||||
typedef enum bit [1:0] {
|
typedef enum bit [1:0] {
|
||||||
TX_STATE_IDLE,
|
TX_STATE_IDLE,
|
||||||
TX_STATE_DATA,
|
TX_STATE_DATA,
|
||||||
TX_STATE_STOP
|
TX_STATE_STOP,
|
||||||
|
TX_STATE_STOP_WAIT
|
||||||
} e_tx_state;
|
} e_tx_state;
|
||||||
|
|
||||||
e_tx_state tx_state;
|
e_tx_state tx_state;
|
||||||
@ -278,12 +280,14 @@ module n64_si (
|
|||||||
|
|
||||||
if (reset) begin
|
if (reset) begin
|
||||||
tx_state <= TX_STATE_IDLE;
|
tx_state <= TX_STATE_IDLE;
|
||||||
|
si_dq_in_inhibit <= 1'b0;
|
||||||
end else begin
|
end else begin
|
||||||
case (tx_state)
|
case (tx_state)
|
||||||
TX_STATE_IDLE: begin
|
TX_STATE_IDLE: begin
|
||||||
if (tx_start) begin
|
if (tx_start) begin
|
||||||
tx_byte_counter <= 4'd0;
|
tx_byte_counter <= 4'd0;
|
||||||
tx_state <= TX_STATE_DATA;
|
tx_state <= TX_STATE_DATA;
|
||||||
|
si_dq_in_inhibit <= 1'b1;
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -299,7 +303,14 @@ module n64_si (
|
|||||||
TX_STATE_STOP: begin
|
TX_STATE_STOP: begin
|
||||||
tx_stop <= 1'b1;
|
tx_stop <= 1'b1;
|
||||||
if (!tx_busy && tx_stop) begin
|
if (!tx_busy && tx_stop) begin
|
||||||
|
tx_state <= TX_STATE_STOP_WAIT;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
TX_STATE_STOP_WAIT: begin
|
||||||
|
if (!tx_busy) begin
|
||||||
tx_state <= TX_STATE_IDLE;
|
tx_state <= TX_STATE_IDLE;
|
||||||
|
si_dq_in_inhibit <= 1'b0;
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
endcase
|
endcase
|
||||||
@ -382,7 +393,7 @@ module n64_si (
|
|||||||
4'd1: {rtc_time_wp, rtc_backup_wp} <= rx_byte_data[1:0];
|
4'd1: {rtc_time_wp, rtc_backup_wp} <= rx_byte_data[1:0];
|
||||||
4'd2: begin
|
4'd2: begin
|
||||||
rtc_stopped <= rx_byte_data[2:1];
|
rtc_stopped <= rx_byte_data[2:1];
|
||||||
if (rx_byte_data[2:1] == 2'b00) begin
|
if ((|rtc_stopped) && (rx_byte_data[2:1] == 2'b00)) begin
|
||||||
n64_scb.rtc_pending <= 1'b1;
|
n64_scb.rtc_pending <= 1'b1;
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -68,7 +68,7 @@ const uint8_t font_data[96][FONT_CHAR_BYTES] = {
|
|||||||
{ 0x38, 0x30, 0x30, 0x30, 0x30, 0x30, 0x38, 0x00, },
|
{ 0x38, 0x30, 0x30, 0x30, 0x30, 0x30, 0x38, 0x00, },
|
||||||
{ 0x00, 0x38, 0x6C, 0x00, 0x00, 0x00, 0x00, 0x00, },
|
{ 0x00, 0x38, 0x6C, 0x00, 0x00, 0x00, 0x00, 0x00, },
|
||||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, },
|
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, },
|
||||||
{ 0x00, 0x18, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, },
|
{ 0x1C, 0x63, 0x63, 0x1C, 0x00, 0x00, 0x00, 0x00, },
|
||||||
{ 0x00, 0x3C, 0x60, 0x7C, 0x66, 0x66, 0x7C, 0x00, },
|
{ 0x00, 0x3C, 0x60, 0x7C, 0x66, 0x66, 0x7C, 0x00, },
|
||||||
{ 0x06, 0x06, 0x3E, 0x66, 0x66, 0x66, 0x3E, 0x00, },
|
{ 0x06, 0x06, 0x3E, 0x66, 0x66, 0x66, 0x3E, 0x00, },
|
||||||
{ 0x00, 0x3C, 0x66, 0x06, 0x06, 0x06, 0x7C, 0x00, },
|
{ 0x00, 0x3C, 0x66, 0x06, 0x06, 0x06, 0x7C, 0x00, },
|
||||||
|
@ -48,6 +48,7 @@ typedef enum {
|
|||||||
CMD_ID_FLASH_PROGRAM = 'K',
|
CMD_ID_FLASH_PROGRAM = 'K',
|
||||||
CMD_ID_FLASH_WAIT_BUSY = 'p',
|
CMD_ID_FLASH_WAIT_BUSY = 'p',
|
||||||
CMD_ID_FLASH_ERASE_BLOCK = 'P',
|
CMD_ID_FLASH_ERASE_BLOCK = 'P',
|
||||||
|
CMD_ID_DIAGNOSTIC_GET = '%',
|
||||||
} sc64_cmd_id_t;
|
} sc64_cmd_id_t;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
@ -436,3 +437,14 @@ sc64_error_t sc64_flash_erase_block (void *address) {
|
|||||||
};
|
};
|
||||||
return sc64_execute_cmd(&cmd);
|
return sc64_execute_cmd(&cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
sc64_error_t sc64_get_diagnostic (sc64_diagnostic_id_t id, uint32_t *value) {
|
||||||
|
sc64_cmd_t cmd = {
|
||||||
|
.id = CMD_ID_DIAGNOSTIC_GET,
|
||||||
|
.arg = { id }
|
||||||
|
};
|
||||||
|
sc64_error_t error = sc64_execute_cmd(&cmd);
|
||||||
|
*value = cmd.rsp[1];
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
@ -93,6 +93,10 @@ typedef enum {
|
|||||||
BUTTON_MODE_DD_DISK_SWAP,
|
BUTTON_MODE_DD_DISK_SWAP,
|
||||||
} sc64_button_mode_t;
|
} sc64_button_mode_t;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
DIAGNOSTIC_ID_VOLTAGE_TEMPERATURE,
|
||||||
|
} sc64_diagnostic_id_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
sc64_boot_mode_t boot_mode;
|
sc64_boot_mode_t boot_mode;
|
||||||
sc64_cic_seed_t cic_seed;
|
sc64_cic_seed_t cic_seed;
|
||||||
@ -174,5 +178,7 @@ sc64_error_t sc64_flash_wait_busy (void);
|
|||||||
sc64_error_t sc64_flash_get_erase_block_size (size_t *erase_block_size);
|
sc64_error_t sc64_flash_get_erase_block_size (size_t *erase_block_size);
|
||||||
sc64_error_t sc64_flash_erase_block (void *address);
|
sc64_error_t sc64_flash_erase_block (void *address);
|
||||||
|
|
||||||
|
sc64_error_t sc64_get_diagnostic (sc64_diagnostic_id_t id, uint32_t *value);
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -10,24 +10,46 @@
|
|||||||
|
|
||||||
static void test_sc64_cfg (void) {
|
static void test_sc64_cfg (void) {
|
||||||
sc64_error_t error;
|
sc64_error_t error;
|
||||||
|
uint32_t button_state;
|
||||||
uint32_t identifier;
|
uint32_t identifier;
|
||||||
uint16_t major;
|
uint16_t major;
|
||||||
uint16_t minor;
|
uint16_t minor;
|
||||||
uint32_t revision;
|
uint32_t revision;
|
||||||
|
uint32_t tmp;
|
||||||
|
|
||||||
|
display_printf("Waiting for the button to be released... ");
|
||||||
|
|
||||||
|
do {
|
||||||
|
if ((error = sc64_get_config(CFG_ID_BUTTON_STATE, &button_state)) != SC64_OK) {
|
||||||
|
error_display("Command CONFIG_GET [BUTTON_STATE] failed: %d", error);
|
||||||
|
}
|
||||||
|
} while (button_state != 0);
|
||||||
|
|
||||||
|
display_printf("done\n\n");
|
||||||
|
|
||||||
if ((error = sc64_get_identifier(&identifier)) != SC64_OK) {
|
if ((error = sc64_get_identifier(&identifier)) != SC64_OK) {
|
||||||
error_display("Command IDENTIFIER_GET failed: %d", error);
|
error_display("Command IDENTIFIER_GET failed: %d", error);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((error = sc64_get_version(&major, &minor, &revision)) != SC64_OK) {
|
if ((error = sc64_get_version(&major, &minor, &revision)) != SC64_OK) {
|
||||||
error_display("Command VERSION_GET failed: %d", error);
|
error_display("Command VERSION_GET failed: %d", error);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
display_printf("Identifier: 0x%08X\n\n", identifier);
|
if ((error = sc64_get_diagnostic(DIAGNOSTIC_ID_VOLTAGE_TEMPERATURE, &tmp)) != SC64_OK) {
|
||||||
|
error_display("Command DIAGNOSTIC_GET failed: %d", error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
display_printf("SC64 firmware version: %d.%d.%d\n", major, minor, revision);
|
uint16_t voltage = (uint16_t) (tmp >> 16);
|
||||||
|
int16_t temperature = (int16_t) (tmp & 0xFFFF);
|
||||||
|
|
||||||
|
display_printf("Identifier: 0x%08X\n", identifier);
|
||||||
|
display_printf("SC64 firmware version: %d.%d.%d\n\n", major, minor, revision);
|
||||||
|
|
||||||
|
display_printf("Voltage: %d.%03d V\n", (voltage / 1000), (voltage % 1000));
|
||||||
|
display_printf("Temperature: %d.%01d `C\n", (temperature / 10), (temperature % 10));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_rtc (void) {
|
static void test_rtc (void) {
|
||||||
@ -233,7 +255,7 @@ bool test_check (void) {
|
|||||||
error_display("Command CONFIG_GET [BUTTON_STATE] failed: %d", error);
|
error_display("Command CONFIG_GET [BUTTON_STATE] failed: %d", error);
|
||||||
}
|
}
|
||||||
|
|
||||||
return button_state != 0;
|
return (button_state != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct {
|
static struct {
|
||||||
|
@ -24,7 +24,7 @@ SECTIONS {
|
|||||||
.text : {
|
.text : {
|
||||||
. = ALIGN(4);
|
. = ALIGN(4);
|
||||||
*(.text)
|
*(.text)
|
||||||
*(.text*)
|
*(.text*)
|
||||||
*(.glue_7)
|
*(.glue_7)
|
||||||
*(.glue_7t)
|
*(.glue_7t)
|
||||||
. = ALIGN(4);
|
. = ALIGN(4);
|
||||||
|
@ -14,14 +14,12 @@ SRC_FILES = \
|
|||||||
flash.c \
|
flash.c \
|
||||||
flashram.c \
|
flashram.c \
|
||||||
fpga.c \
|
fpga.c \
|
||||||
gvr.c \
|
|
||||||
hw.c \
|
hw.c \
|
||||||
isv.c \
|
isv.c \
|
||||||
lcmxo2.c \
|
lcmxo2.c \
|
||||||
led.c \
|
led.c \
|
||||||
rtc.c \
|
rtc.c \
|
||||||
sd.c \
|
sd.c \
|
||||||
task.c \
|
|
||||||
timer.c \
|
timer.c \
|
||||||
update.c \
|
update.c \
|
||||||
usb.c \
|
usb.c \
|
||||||
|
@ -23,7 +23,7 @@ SECTIONS {
|
|||||||
. = ALIGN(4);
|
. = ALIGN(4);
|
||||||
_stext = .;
|
_stext = .;
|
||||||
*(.text)
|
*(.text)
|
||||||
*(.text*)
|
*(.text*)
|
||||||
*(.glue_7)
|
*(.glue_7)
|
||||||
*(.glue_7t)
|
*(.glue_7t)
|
||||||
. = ALIGN(4);
|
. = ALIGN(4);
|
||||||
|
@ -16,7 +16,7 @@ SECTIONS {
|
|||||||
.text : {
|
.text : {
|
||||||
. = ALIGN(4);
|
. = ALIGN(4);
|
||||||
*(.text)
|
*(.text)
|
||||||
*(.text*)
|
*(.text*)
|
||||||
*(.glue_7)
|
*(.glue_7)
|
||||||
*(.glue_7t)
|
*(.glue_7t)
|
||||||
. = ALIGN(4);
|
. = ALIGN(4);
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
.type loader, %object
|
.type loader, %object
|
||||||
loader:
|
loader:
|
||||||
.incbin "build/loader/loader.bin"
|
.incbin "build/loader/loader.bin"
|
||||||
|
.org 0x1000, 0xFF
|
||||||
|
|
||||||
.section .text.Reset_Handler
|
.section .text.Reset_Handler
|
||||||
.type Reset_Handler, %function
|
.type Reset_Handler, %function
|
||||||
|
@ -1,34 +1,51 @@
|
|||||||
#include "app.h"
|
#include <stdbool.h>
|
||||||
#include "gvr.h"
|
#include "button.h"
|
||||||
|
#include "cfg.h"
|
||||||
|
#include "cic.h"
|
||||||
|
#include "dd.h"
|
||||||
|
#include "flashram.h"
|
||||||
|
#include "fpga.h"
|
||||||
#include "hw.h"
|
#include "hw.h"
|
||||||
|
#include "isv.h"
|
||||||
#include "led.h"
|
#include "led.h"
|
||||||
#include "rtc.h"
|
#include "rtc.h"
|
||||||
#include "task.h"
|
#include "sd.h"
|
||||||
|
#include "timer.h"
|
||||||
|
#include "usb.h"
|
||||||
|
#include "writeback.h"
|
||||||
|
|
||||||
|
|
||||||
#define RTC_STACK_SIZE (256)
|
|
||||||
#define LED_STACK_SIZE (256)
|
|
||||||
#define GVR_STACK_SIZE (2048)
|
|
||||||
|
|
||||||
|
|
||||||
uint8_t rtc_stack[RTC_STACK_SIZE] __attribute__((aligned(8)));
|
|
||||||
uint8_t led_stack[LED_STACK_SIZE] __attribute__((aligned(8)));
|
|
||||||
uint8_t gvr_stack[GVR_STACK_SIZE] __attribute__((aligned(8)));
|
|
||||||
|
|
||||||
|
|
||||||
void app_get_stack_usage (uint32_t *usage) {
|
|
||||||
*usage++ = 0;
|
|
||||||
*usage++ = task_get_stack_usage(rtc_stack, RTC_STACK_SIZE);
|
|
||||||
*usage++ = task_get_stack_usage(led_stack, LED_STACK_SIZE);
|
|
||||||
*usage++ = task_get_stack_usage(gvr_stack, GVR_STACK_SIZE);
|
|
||||||
}
|
|
||||||
|
|
||||||
void app (void) {
|
void app (void) {
|
||||||
hw_init();
|
hw_app_init();
|
||||||
|
|
||||||
task_create(TASK_ID_RTC, rtc_task, rtc_stack, RTC_STACK_SIZE);
|
timer_init();
|
||||||
task_create(TASK_ID_LED, led_task, led_stack, LED_STACK_SIZE);
|
|
||||||
task_create(TASK_ID_GVR, gvr_task, gvr_stack, GVR_STACK_SIZE);
|
|
||||||
|
|
||||||
task_scheduler_start();
|
while (fpga_id_get() != FPGA_ID);
|
||||||
|
|
||||||
|
rtc_init();
|
||||||
|
|
||||||
|
button_init();
|
||||||
|
cfg_init();
|
||||||
|
cic_init();
|
||||||
|
dd_init();
|
||||||
|
flashram_init();
|
||||||
|
isv_init();
|
||||||
|
led_init();
|
||||||
|
sd_init();
|
||||||
|
usb_init();
|
||||||
|
writeback_init();
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
button_process();
|
||||||
|
cfg_process();
|
||||||
|
cic_process();
|
||||||
|
dd_process();
|
||||||
|
flashram_process();
|
||||||
|
isv_process();
|
||||||
|
led_process();
|
||||||
|
rtc_process();
|
||||||
|
sd_process();
|
||||||
|
usb_process();
|
||||||
|
writeback_process();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,11 +0,0 @@
|
|||||||
#ifndef APP_H__
|
|
||||||
#define APP_H__
|
|
||||||
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
|
|
||||||
void app_get_stack_usage (uint32_t *usage);
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
@ -25,7 +25,7 @@ bool button_get_state (void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool button_set_mode (button_mode_t mode) {
|
bool button_set_mode (button_mode_t mode) {
|
||||||
if (mode > BUTTON_MODE_DD_DISK_SWAP) {
|
if (mode >= __BUTTON_MODE_COUNT) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
p.mode = mode;
|
p.mode = mode;
|
||||||
@ -39,6 +39,7 @@ button_mode_t button_get_mode (void) {
|
|||||||
return p.mode;
|
return p.mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void button_init (void) {
|
void button_init (void) {
|
||||||
p.counter = 0;
|
p.counter = 0;
|
||||||
p.state = false;
|
p.state = false;
|
||||||
@ -46,9 +47,12 @@ void button_init (void) {
|
|||||||
p.trigger = false;
|
p.trigger = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void button_process (void) {
|
void button_process (void) {
|
||||||
usb_tx_info_t packet_info;
|
usb_tx_info_t packet_info;
|
||||||
|
|
||||||
uint32_t status = fpga_reg_get(REG_CFG_SCR);
|
uint32_t status = fpga_reg_get(REG_CFG_SCR);
|
||||||
|
|
||||||
if (status & CFG_SCR_BUTTON_STATE) {
|
if (status & CFG_SCR_BUTTON_STATE) {
|
||||||
if (p.counter < BUTTON_COUNTER_TRIGGER_ON) {
|
if (p.counter < BUTTON_COUNTER_TRIGGER_ON) {
|
||||||
p.counter += 1;
|
p.counter += 1;
|
||||||
@ -58,13 +62,16 @@ void button_process (void) {
|
|||||||
p.counter -= 1;
|
p.counter -= 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!p.state && p.counter == BUTTON_COUNTER_TRIGGER_ON) {
|
if (!p.state && p.counter == BUTTON_COUNTER_TRIGGER_ON) {
|
||||||
p.state = true;
|
p.state = true;
|
||||||
p.trigger = true;
|
p.trigger = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (p.state && p.counter == BUTTON_COUNTER_TRIGGER_OFF) {
|
if (p.state && p.counter == BUTTON_COUNTER_TRIGGER_OFF) {
|
||||||
p.state = false;
|
p.state = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (p.trigger) {
|
if (p.trigger) {
|
||||||
switch (p.mode) {
|
switch (p.mode) {
|
||||||
case BUTTON_MODE_N64_IRQ:
|
case BUTTON_MODE_N64_IRQ:
|
||||||
|
@ -6,17 +6,20 @@
|
|||||||
|
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
BUTTON_MODE_NONE,
|
BUTTON_MODE_NONE = 0,
|
||||||
BUTTON_MODE_N64_IRQ,
|
BUTTON_MODE_N64_IRQ = 1,
|
||||||
BUTTON_MODE_USB_PACKET,
|
BUTTON_MODE_USB_PACKET = 2,
|
||||||
BUTTON_MODE_DD_DISK_SWAP,
|
BUTTON_MODE_DD_DISK_SWAP = 3,
|
||||||
|
__BUTTON_MODE_COUNT
|
||||||
} button_mode_t;
|
} button_mode_t;
|
||||||
|
|
||||||
|
|
||||||
bool button_get_state (void);
|
bool button_get_state (void);
|
||||||
bool button_set_mode (button_mode_t mode);
|
bool button_set_mode (button_mode_t mode);
|
||||||
button_mode_t button_get_mode (void);
|
button_mode_t button_get_mode (void);
|
||||||
|
|
||||||
void button_init (void);
|
void button_init (void);
|
||||||
|
|
||||||
void button_process (void);
|
void button_process (void);
|
||||||
|
|
||||||
|
|
||||||
|
@ -4,7 +4,9 @@
|
|||||||
#include "dd.h"
|
#include "dd.h"
|
||||||
#include "flash.h"
|
#include "flash.h"
|
||||||
#include "fpga.h"
|
#include "fpga.h"
|
||||||
|
#include "hw.h"
|
||||||
#include "isv.h"
|
#include "isv.h"
|
||||||
|
#include "led.h"
|
||||||
#include "rtc.h"
|
#include "rtc.h"
|
||||||
#include "sd.h"
|
#include "sd.h"
|
||||||
#include "usb.h"
|
#include "usb.h"
|
||||||
@ -17,25 +19,25 @@
|
|||||||
|
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
CFG_ID_BOOTLOADER_SWITCH,
|
CFG_ID_BOOTLOADER_SWITCH = 0,
|
||||||
CFG_ID_ROM_WRITE_ENABLE,
|
CFG_ID_ROM_WRITE_ENABLE = 1,
|
||||||
CFG_ID_ROM_SHADOW_ENABLE,
|
CFG_ID_ROM_SHADOW_ENABLE = 2,
|
||||||
CFG_ID_DD_MODE,
|
CFG_ID_DD_MODE = 3,
|
||||||
CFG_ID_ISV_ADDRESS,
|
CFG_ID_ISV_ADDRESS = 4,
|
||||||
CFG_ID_BOOT_MODE,
|
CFG_ID_BOOT_MODE = 5,
|
||||||
CFG_ID_SAVE_TYPE,
|
CFG_ID_SAVE_TYPE = 6,
|
||||||
CFG_ID_CIC_SEED,
|
CFG_ID_CIC_SEED = 7,
|
||||||
CFG_ID_TV_TYPE,
|
CFG_ID_TV_TYPE = 8,
|
||||||
CFG_ID_DD_SD_ENABLE,
|
CFG_ID_DD_SD_ENABLE = 9,
|
||||||
CFG_ID_DD_DRIVE_TYPE,
|
CFG_ID_DD_DRIVE_TYPE = 10,
|
||||||
CFG_ID_DD_DISK_STATE,
|
CFG_ID_DD_DISK_STATE = 11,
|
||||||
CFG_ID_BUTTON_STATE,
|
CFG_ID_BUTTON_STATE = 12,
|
||||||
CFG_ID_BUTTON_MODE,
|
CFG_ID_BUTTON_MODE = 13,
|
||||||
CFG_ID_ROM_EXTENDED_ENABLE,
|
CFG_ID_ROM_EXTENDED_ENABLE = 14,
|
||||||
} cfg_id_t;
|
} cfg_id_t;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
SETTING_ID_LED_ENABLE,
|
SETTING_ID_LED_ENABLE = 0,
|
||||||
} setting_id_t;
|
} setting_id_t;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
@ -83,6 +85,10 @@ typedef enum {
|
|||||||
SD_CARD_OP_BYTE_SWAP_OFF = 5,
|
SD_CARD_OP_BYTE_SWAP_OFF = 5,
|
||||||
} sd_card_op_t;
|
} sd_card_op_t;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
DIAGNOSTIC_ID_VOLTAGE_TEMPERATURE = 0,
|
||||||
|
} diagnostic_id_t;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
SDRAM = (1 << 0),
|
SDRAM = (1 << 0),
|
||||||
FLASH = (1 << 1),
|
FLASH = (1 << 1),
|
||||||
@ -178,7 +184,7 @@ static void cfg_change_scr_bits (uint32_t mask, bool value) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static bool cfg_set_save_type (save_type_t save_type) {
|
static bool cfg_set_save_type (save_type_t save_type) {
|
||||||
if (save_type > SAVE_TYPE_SRAM_1M) {
|
if (save_type >= __SAVE_TYPE_COUNT) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -225,6 +231,22 @@ static bool cfg_set_save_type (save_type_t save_type) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool cfg_read_diagnostic_data (uint32_t *args) {
|
||||||
|
switch (args[0]) {
|
||||||
|
case DIAGNOSTIC_ID_VOLTAGE_TEMPERATURE: {
|
||||||
|
uint16_t voltage;
|
||||||
|
int16_t temperature;
|
||||||
|
hw_adc_read_voltage_temperature(&voltage, &temperature);
|
||||||
|
args[1] = ((uint32_t) (voltage) << 16) | ((uint32_t) (temperature));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
uint32_t cfg_get_identifier (void) {
|
uint32_t cfg_get_identifier (void) {
|
||||||
return fpga_reg_get(REG_CFG_IDENTIFIER);
|
return fpga_reg_get(REG_CFG_IDENTIFIER);
|
||||||
@ -373,11 +395,11 @@ bool cfg_update (uint32_t *args) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool cfg_query_setting (uint32_t *args) {
|
bool cfg_query_setting (uint32_t *args) {
|
||||||
rtc_settings_t settings = (*rtc_get_settings());
|
rtc_settings_t *settings = rtc_get_settings();
|
||||||
|
|
||||||
switch (args[0]) {
|
switch (args[0]) {
|
||||||
case SETTING_ID_LED_ENABLE:
|
case SETTING_ID_LED_ENABLE:
|
||||||
args[1] = settings.led_enabled;
|
args[1] = settings->led_enabled;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return true;
|
return true;
|
||||||
@ -387,17 +409,17 @@ bool cfg_query_setting (uint32_t *args) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool cfg_update_setting (uint32_t *args) {
|
bool cfg_update_setting (uint32_t *args) {
|
||||||
rtc_settings_t settings = (*rtc_get_settings());
|
rtc_settings_t *settings = rtc_get_settings();
|
||||||
|
|
||||||
switch (args[0]) {
|
switch (args[0]) {
|
||||||
case SETTING_ID_LED_ENABLE:
|
case SETTING_ID_LED_ENABLE:
|
||||||
settings.led_enabled = args[1];
|
settings->led_enabled = args[1];
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
rtc_set_settings(&settings);
|
rtc_save_settings();
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -450,12 +472,14 @@ void cfg_reset_state (void) {
|
|||||||
p.boot_mode = BOOT_MODE_MENU;
|
p.boot_mode = BOOT_MODE_MENU;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void cfg_init (void) {
|
void cfg_init (void) {
|
||||||
fpga_reg_set(REG_CFG_SCR, CFG_SCR_BOOTLOADER_ENABLED);
|
fpga_reg_set(REG_CFG_SCR, CFG_SCR_BOOTLOADER_ENABLED);
|
||||||
cfg_reset_state();
|
cfg_reset_state();
|
||||||
p.usb_output_ready = true;
|
p.usb_output_ready = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void cfg_process (void) {
|
void cfg_process (void) {
|
||||||
uint32_t reg;
|
uint32_t reg;
|
||||||
uint32_t args[2];
|
uint32_t args[2];
|
||||||
@ -558,12 +582,16 @@ void cfg_process (void) {
|
|||||||
case SD_CARD_OP_DEINIT:
|
case SD_CARD_OP_DEINIT:
|
||||||
sd_card_deinit();
|
sd_card_deinit();
|
||||||
break;
|
break;
|
||||||
case SD_CARD_OP_INIT:
|
case SD_CARD_OP_INIT: {
|
||||||
if (sd_card_init()) {
|
led_activity_on();
|
||||||
|
bool error = sd_card_init();
|
||||||
|
led_activity_off();
|
||||||
|
if (error) {
|
||||||
cfg_set_error(CFG_ERROR_SD_CARD);
|
cfg_set_error(CFG_ERROR_SD_CARD);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case SD_CARD_OP_GET_STATUS:
|
case SD_CARD_OP_GET_STATUS:
|
||||||
args[1] = sd_card_get_status();
|
args[1] = sd_card_get_status();
|
||||||
break;
|
break;
|
||||||
@ -599,7 +627,7 @@ void cfg_process (void) {
|
|||||||
p.sd_card_sector = args[0];
|
p.sd_card_sector = args[0];
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 's':
|
case 's': {
|
||||||
if (args[1] >= 0x800000) {
|
if (args[1] >= 0x800000) {
|
||||||
cfg_set_error(CFG_ERROR_BAD_ARGUMENT);
|
cfg_set_error(CFG_ERROR_BAD_ARGUMENT);
|
||||||
return;
|
return;
|
||||||
@ -608,14 +636,18 @@ void cfg_process (void) {
|
|||||||
cfg_set_error(CFG_ERROR_BAD_ADDRESS);
|
cfg_set_error(CFG_ERROR_BAD_ADDRESS);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (sd_read_sectors(args[0], p.sd_card_sector, args[1])) {
|
led_activity_on();
|
||||||
|
bool error = sd_read_sectors(args[0], p.sd_card_sector, args[1]);
|
||||||
|
led_activity_off();
|
||||||
|
if (error) {
|
||||||
cfg_set_error(CFG_ERROR_SD_CARD);
|
cfg_set_error(CFG_ERROR_SD_CARD);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
p.sd_card_sector += args[1];
|
p.sd_card_sector += args[1];
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case 'S':
|
case 'S': {
|
||||||
if (args[1] >= 0x800000) {
|
if (args[1] >= 0x800000) {
|
||||||
cfg_set_error(CFG_ERROR_BAD_ARGUMENT);
|
cfg_set_error(CFG_ERROR_BAD_ARGUMENT);
|
||||||
return;
|
return;
|
||||||
@ -624,12 +656,16 @@ void cfg_process (void) {
|
|||||||
cfg_set_error(CFG_ERROR_BAD_ADDRESS);
|
cfg_set_error(CFG_ERROR_BAD_ADDRESS);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (sd_write_sectors(args[0], p.sd_card_sector, args[1])) {
|
led_activity_on();
|
||||||
|
bool error = sd_write_sectors(args[0], p.sd_card_sector, args[1]);
|
||||||
|
led_activity_off();
|
||||||
|
if (error) {
|
||||||
cfg_set_error(CFG_ERROR_SD_CARD);
|
cfg_set_error(CFG_ERROR_SD_CARD);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
p.sd_card_sector += args[1];
|
p.sd_card_sector += args[1];
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case 'D':
|
case 'D':
|
||||||
if (cfg_translate_address(&args[0], args[1], (SDRAM | BRAM))) {
|
if (cfg_translate_address(&args[0], args[1], (SDRAM | BRAM))) {
|
||||||
@ -685,6 +721,13 @@ void cfg_process (void) {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case '%':
|
||||||
|
if (cfg_read_diagnostic_data(args)) {
|
||||||
|
cfg_set_error(CFG_ERROR_BAD_CONFIG_ID);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
cfg_set_error(CFG_ERROR_UNKNOWN_CMD);
|
cfg_set_error(CFG_ERROR_UNKNOWN_CMD);
|
||||||
return;
|
return;
|
||||||
|
@ -14,6 +14,7 @@ typedef enum {
|
|||||||
SAVE_TYPE_FLASHRAM = 4,
|
SAVE_TYPE_FLASHRAM = 4,
|
||||||
SAVE_TYPE_SRAM_BANKED = 5,
|
SAVE_TYPE_SRAM_BANKED = 5,
|
||||||
SAVE_TYPE_SRAM_1M = 6,
|
SAVE_TYPE_SRAM_1M = 6,
|
||||||
|
__SAVE_TYPE_COUNT
|
||||||
} save_type_t;
|
} save_type_t;
|
||||||
|
|
||||||
|
|
||||||
@ -27,7 +28,9 @@ save_type_t cfg_get_save_type (void);
|
|||||||
void cfg_get_time (uint32_t *args);
|
void cfg_get_time (uint32_t *args);
|
||||||
void cfg_set_time (uint32_t *args);
|
void cfg_set_time (uint32_t *args);
|
||||||
void cfg_reset_state (void);
|
void cfg_reset_state (void);
|
||||||
|
|
||||||
void cfg_init (void);
|
void cfg_init (void);
|
||||||
|
|
||||||
void cfg_process (void);
|
void cfg_process (void);
|
||||||
|
|
||||||
|
|
||||||
|
@ -12,12 +12,7 @@ typedef enum {
|
|||||||
} cic_region_t;
|
} cic_region_t;
|
||||||
|
|
||||||
|
|
||||||
static bool cic_initialized = false;
|
static bool cic_error_active = false;
|
||||||
|
|
||||||
|
|
||||||
static void cic_irq_reset_falling (void) {
|
|
||||||
led_clear_error(LED_ERROR_CIC);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void cic_reset_parameters (void) {
|
void cic_reset_parameters (void) {
|
||||||
@ -26,72 +21,70 @@ void cic_reset_parameters (void) {
|
|||||||
const uint8_t default_seed = 0x3F;
|
const uint8_t default_seed = 0x3F;
|
||||||
const uint64_t default_checksum = 0xA536C0F1D859ULL;
|
const uint64_t default_checksum = 0xA536C0F1D859ULL;
|
||||||
|
|
||||||
uint32_t cic_config_0 = (default_seed << CIC_SEED_BIT) | ((default_checksum >> 32) & 0xFFFF);
|
uint32_t cfg[2] = {
|
||||||
uint32_t cic_config_1 = (default_checksum & 0xFFFFFFFFUL);
|
(default_seed << CIC_SEED_BIT) | ((default_checksum >> 32) & 0xFFFF),
|
||||||
|
(default_checksum & 0xFFFFFFFFUL)
|
||||||
|
};
|
||||||
|
|
||||||
if (region == REGION_PAL) {
|
if (region == REGION_PAL) {
|
||||||
cic_config_0 |= CIC_REGION;
|
cfg[0] |= CIC_REGION;
|
||||||
}
|
}
|
||||||
|
|
||||||
fpga_reg_set(REG_CIC_0, cic_config_0);
|
fpga_reg_set(REG_CIC_0, cfg[0]);
|
||||||
fpga_reg_set(REG_CIC_1, cic_config_1);
|
fpga_reg_set(REG_CIC_1, cfg[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void cic_set_parameters (uint32_t *args) {
|
void cic_set_parameters (uint32_t *args) {
|
||||||
uint32_t cic_config_0 = args[0] & (0x00FFFFFF);
|
uint32_t cfg[2] = {
|
||||||
uint32_t cic_config_1 = args[1];
|
args[0] & (0x00FFFFFF),
|
||||||
|
args[1]
|
||||||
|
};
|
||||||
|
|
||||||
cic_config_0 |= fpga_reg_get(REG_CIC_0) & (CIC_64DD_MODE | CIC_REGION);
|
cfg[0] |= fpga_reg_get(REG_CIC_0) & (CIC_64DD_MODE | CIC_REGION);
|
||||||
|
|
||||||
if (args[0] & (1 << 24)) {
|
if (args[0] & (1 << 24)) {
|
||||||
cic_config_0 |= CIC_DISABLED;
|
cfg[0] |= CIC_DISABLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
fpga_reg_set(REG_CIC_0, cic_config_0);
|
fpga_reg_set(REG_CIC_0, cfg[0]);
|
||||||
fpga_reg_set(REG_CIC_1, cic_config_1);
|
fpga_reg_set(REG_CIC_1, cfg[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void cic_set_dd_mode (bool enabled) {
|
void cic_set_dd_mode (bool enabled) {
|
||||||
uint32_t cic_config_0 = fpga_reg_get(REG_CIC_0);
|
uint32_t cfg = fpga_reg_get(REG_CIC_0);
|
||||||
|
|
||||||
if (enabled) {
|
if (enabled) {
|
||||||
cic_config_0 |= CIC_64DD_MODE;
|
cfg |= CIC_64DD_MODE;
|
||||||
} else {
|
} else {
|
||||||
cic_config_0 &= ~(CIC_64DD_MODE);
|
cfg &= ~(CIC_64DD_MODE);
|
||||||
}
|
}
|
||||||
|
|
||||||
fpga_reg_set(REG_CIC_0, cic_config_0);
|
fpga_reg_set(REG_CIC_0, cfg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void cic_init (void) {
|
void cic_init (void) {
|
||||||
hw_gpio_irq_setup(GPIO_ID_N64_RESET, GPIO_IRQ_FALLING, cic_irq_reset_falling);
|
cic_reset_parameters();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void cic_process (void) {
|
void cic_process (void) {
|
||||||
if (!cic_initialized) {
|
uint32_t cfg = fpga_reg_get(REG_CIC_0);
|
||||||
if (rtc_is_initialized()) {
|
|
||||||
cic_reset_parameters();
|
|
||||||
cic_initialized = true;
|
|
||||||
} else {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t cic_config_0 = fpga_reg_get(REG_CIC_0);
|
if (cfg & CIC_INVALID_REGION_DETECTED) {
|
||||||
|
cfg ^= CIC_REGION;
|
||||||
|
cfg |= CIC_INVALID_REGION_RESET;
|
||||||
|
fpga_reg_set(REG_CIC_0, cfg);
|
||||||
|
|
||||||
if (cic_config_0 & CIC_INVALID_REGION_DETECTED) {
|
cic_region_t region = (cfg & CIC_REGION) ? REGION_PAL : REGION_NTSC;
|
||||||
cic_config_0 ^= CIC_REGION;
|
rtc_set_region(region);
|
||||||
cic_config_0 |= CIC_INVALID_REGION_RESET;
|
|
||||||
fpga_reg_set(REG_CIC_0, cic_config_0);
|
|
||||||
|
|
||||||
if (cic_config_0 & CIC_REGION) {
|
|
||||||
rtc_set_region(REGION_PAL);
|
|
||||||
} else {
|
|
||||||
rtc_set_region(REGION_NTSC);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
cic_error_active = true;
|
||||||
led_blink_error(LED_ERROR_CIC);
|
led_blink_error(LED_ERROR_CIC);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (cic_error_active && (!hw_gpio_get(GPIO_ID_N64_RESET))) {
|
||||||
|
cic_error_active = false;
|
||||||
|
led_clear_error(LED_ERROR_CIC);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,9 @@
|
|||||||
void cic_reset_parameters (void);
|
void cic_reset_parameters (void);
|
||||||
void cic_set_parameters (uint32_t *args);
|
void cic_set_parameters (uint32_t *args);
|
||||||
void cic_set_dd_mode (bool enabled);
|
void cic_set_dd_mode (bool enabled);
|
||||||
|
|
||||||
void cic_init (void);
|
void cic_init (void);
|
||||||
|
|
||||||
void cic_process (void);
|
void cic_process (void);
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,10 +1,9 @@
|
|||||||
#include <stdint.h>
|
|
||||||
#include "dd.h"
|
#include "dd.h"
|
||||||
#include "fpga.h"
|
#include "fpga.h"
|
||||||
#include "hw.h"
|
|
||||||
#include "led.h"
|
#include "led.h"
|
||||||
#include "rtc.h"
|
#include "rtc.h"
|
||||||
#include "sd.h"
|
#include "sd.h"
|
||||||
|
#include "timer.h"
|
||||||
#include "usb.h"
|
#include "usb.h"
|
||||||
|
|
||||||
|
|
||||||
@ -20,7 +19,7 @@
|
|||||||
#define DD_DRIVE_ID_DEVELOPMENT (0x0004)
|
#define DD_DRIVE_ID_DEVELOPMENT (0x0004)
|
||||||
#define DD_VERSION_RETAIL (0x0114)
|
#define DD_VERSION_RETAIL (0x0114)
|
||||||
|
|
||||||
#define DD_SPIN_UP_TIME (2000)
|
#define DD_SPIN_UP_TIME_MS (2000)
|
||||||
|
|
||||||
#define DD_THB_UNMAPPED (0xFFFFFFFF)
|
#define DD_THB_UNMAPPED (0xFFFFFFFF)
|
||||||
#define DD_THB_WRITABLE_FLAG (1 << 31)
|
#define DD_THB_WRITABLE_FLAG (1 << 31)
|
||||||
@ -75,7 +74,6 @@ struct process {
|
|||||||
rtc_time_t time;
|
rtc_time_t time;
|
||||||
bool disk_spinning;
|
bool disk_spinning;
|
||||||
bool cmd_response_delayed;
|
bool cmd_response_delayed;
|
||||||
bool cmd_response_ready;
|
|
||||||
bool bm_running;
|
bool bm_running;
|
||||||
bool transfer_mode;
|
bool transfer_mode;
|
||||||
bool full_track_transfer;
|
bool full_track_transfer;
|
||||||
@ -138,7 +136,9 @@ static bool dd_block_read_request (void) {
|
|||||||
if (p.sd_mode) {
|
if (p.sd_mode) {
|
||||||
uint32_t sector_table[DD_SD_SECTOR_TABLE_SIZE];
|
uint32_t sector_table[DD_SD_SECTOR_TABLE_SIZE];
|
||||||
uint32_t sectors = dd_fill_sd_sector_table(index, sector_table, false);
|
uint32_t sectors = dd_fill_sd_sector_table(index, sector_table, false);
|
||||||
|
led_activity_on();
|
||||||
bool error = sd_optimize_sectors(buffer_address, sector_table, sectors, sd_read_sectors);
|
bool error = sd_optimize_sectors(buffer_address, sector_table, sectors, sd_read_sectors);
|
||||||
|
led_activity_off();
|
||||||
dd_set_block_ready(!error);
|
dd_set_block_ready(!error);
|
||||||
} else {
|
} else {
|
||||||
usb_tx_info_t packet_info;
|
usb_tx_info_t packet_info;
|
||||||
@ -160,7 +160,9 @@ static bool dd_block_write_request (void) {
|
|||||||
if (p.sd_mode) {
|
if (p.sd_mode) {
|
||||||
uint32_t sector_table[DD_SD_SECTOR_TABLE_SIZE];
|
uint32_t sector_table[DD_SD_SECTOR_TABLE_SIZE];
|
||||||
uint32_t sectors = dd_fill_sd_sector_table(index, sector_table, true);
|
uint32_t sectors = dd_fill_sd_sector_table(index, sector_table, true);
|
||||||
|
led_activity_on();
|
||||||
bool error = sd_optimize_sectors(buffer_address, sector_table, sectors, sd_write_sectors);
|
bool error = sd_optimize_sectors(buffer_address, sector_table, sectors, sd_write_sectors);
|
||||||
|
led_activity_off();
|
||||||
dd_set_block_ready(!error);
|
dd_set_block_ready(!error);
|
||||||
} else {
|
} else {
|
||||||
usb_tx_info_t packet_info;
|
usb_tx_info_t packet_info;
|
||||||
@ -178,10 +180,6 @@ static bool dd_block_write_request (void) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dd_set_cmd_response_ready (void) {
|
|
||||||
p.cmd_response_ready = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void dd_set_block_ready (bool valid) {
|
void dd_set_block_ready (bool valid) {
|
||||||
p.block_ready = true;
|
p.block_ready = true;
|
||||||
@ -269,7 +267,7 @@ void dd_set_disk_mapping (uint32_t address, uint32_t length) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void dd_handle_button (void) {
|
void dd_handle_button (void) {
|
||||||
led_blink_act();
|
led_activity_pulse();
|
||||||
if (dd_get_disk_state() == DD_DISK_STATE_EJECTED) {
|
if (dd_get_disk_state() == DD_DISK_STATE_EJECTED) {
|
||||||
dd_set_disk_state(DD_DISK_STATE_INSERTED);
|
dd_set_disk_state(DD_DISK_STATE_INSERTED);
|
||||||
} else {
|
} else {
|
||||||
@ -284,13 +282,13 @@ void dd_handle_button (void) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void dd_init (void) {
|
void dd_init (void) {
|
||||||
fpga_reg_set(REG_DD_SCR, 0);
|
fpga_reg_set(REG_DD_SCR, 0);
|
||||||
fpga_reg_set(REG_DD_HEAD_TRACK, 0);
|
fpga_reg_set(REG_DD_HEAD_TRACK, 0);
|
||||||
fpga_reg_set(REG_DD_DRIVE_ID, DD_DRIVE_ID_RETAIL);
|
fpga_reg_set(REG_DD_DRIVE_ID, DD_DRIVE_ID_RETAIL);
|
||||||
p.state = STATE_IDLE;
|
p.state = STATE_IDLE;
|
||||||
p.cmd_response_delayed = false;
|
p.cmd_response_delayed = false;
|
||||||
p.cmd_response_ready = false;
|
|
||||||
p.disk_spinning = false;
|
p.disk_spinning = false;
|
||||||
p.bm_running = false;
|
p.bm_running = false;
|
||||||
p.drive_type = DD_DRIVE_TYPE_RETAIL;
|
p.drive_type = DD_DRIVE_TYPE_RETAIL;
|
||||||
@ -299,6 +297,7 @@ void dd_init (void) {
|
|||||||
dd_set_disk_mapping(0, 0);
|
dd_set_disk_mapping(0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void dd_process (void) {
|
void dd_process (void) {
|
||||||
uint32_t starting_scr = fpga_reg_get(REG_DD_SCR);
|
uint32_t starting_scr = fpga_reg_get(REG_DD_SCR);
|
||||||
uint32_t scr = starting_scr;
|
uint32_t scr = starting_scr;
|
||||||
@ -306,7 +305,6 @@ void dd_process (void) {
|
|||||||
if (scr & DD_SCR_HARD_RESET) {
|
if (scr & DD_SCR_HARD_RESET) {
|
||||||
p.state = STATE_IDLE;
|
p.state = STATE_IDLE;
|
||||||
p.cmd_response_delayed = false;
|
p.cmd_response_delayed = false;
|
||||||
p.cmd_response_ready = false;
|
|
||||||
p.disk_spinning = false;
|
p.disk_spinning = false;
|
||||||
p.bm_running = false;
|
p.bm_running = false;
|
||||||
p.head_track = 0;
|
p.head_track = 0;
|
||||||
@ -319,19 +317,16 @@ void dd_process (void) {
|
|||||||
uint16_t data = cmd_data & 0xFFFF;
|
uint16_t data = cmd_data & 0xFFFF;
|
||||||
|
|
||||||
if (p.cmd_response_delayed) {
|
if (p.cmd_response_delayed) {
|
||||||
if (p.cmd_response_ready) {
|
if (timer_countdown_elapsed(TIMER_ID_DD)) {
|
||||||
p.cmd_response_delayed = false;
|
p.cmd_response_delayed = false;
|
||||||
fpga_reg_set(REG_DD_HEAD_TRACK, DD_HEAD_TRACK_INDEX_LOCK | data);
|
fpga_reg_set(REG_DD_HEAD_TRACK, DD_HEAD_TRACK_INDEX_LOCK | data);
|
||||||
scr |= DD_SCR_CMD_READY;
|
scr |= DD_SCR_CMD_READY;
|
||||||
}
|
}
|
||||||
} else if ((cmd == DD_CMD_SEEK_READ) || (cmd == DD_CMD_SEEK_WRITE)) {
|
} else if ((cmd == DD_CMD_SEEK_READ) || (cmd == DD_CMD_SEEK_WRITE)) {
|
||||||
p.cmd_response_delayed = true;
|
p.cmd_response_delayed = true;
|
||||||
p.cmd_response_ready = false;
|
|
||||||
if (!p.disk_spinning) {
|
if (!p.disk_spinning) {
|
||||||
p.disk_spinning = true;
|
p.disk_spinning = true;
|
||||||
hw_tim_setup(TIM_ID_DD, DD_SPIN_UP_TIME, dd_set_cmd_response_ready);
|
timer_countdown_start(TIMER_ID_DD, DD_SPIN_UP_TIME_MS);
|
||||||
} else {
|
|
||||||
p.cmd_response_ready = true;
|
|
||||||
}
|
}
|
||||||
fpga_reg_set(REG_DD_HEAD_TRACK, p.head_track & ~(DD_HEAD_TRACK_INDEX_LOCK));
|
fpga_reg_set(REG_DD_HEAD_TRACK, p.head_track & ~(DD_HEAD_TRACK_INDEX_LOCK));
|
||||||
p.head_track = data & DD_HEAD_TRACK_MASK;
|
p.head_track = data & DD_HEAD_TRACK_MASK;
|
||||||
@ -397,7 +392,7 @@ void dd_process (void) {
|
|||||||
fpga_reg_set(REG_DD_CMD_DATA, data);
|
fpga_reg_set(REG_DD_CMD_DATA, data);
|
||||||
scr |= DD_SCR_CMD_READY;
|
scr |= DD_SCR_CMD_READY;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (scr & DD_SCR_BM_STOP) {
|
if (scr & DD_SCR_BM_STOP) {
|
||||||
scr |= DD_SCR_BM_STOP_CLEAR;
|
scr |= DD_SCR_BM_STOP_CLEAR;
|
||||||
|
@ -27,7 +27,9 @@ bool dd_get_sd_mode (void);
|
|||||||
void dd_set_sd_mode (bool value);
|
void dd_set_sd_mode (bool value);
|
||||||
void dd_set_disk_mapping (uint32_t address, uint32_t length);
|
void dd_set_disk_mapping (uint32_t address, uint32_t length);
|
||||||
void dd_handle_button (void);
|
void dd_handle_button (void);
|
||||||
|
|
||||||
void dd_init (void);
|
void dd_init (void);
|
||||||
|
|
||||||
void dd_process (void);
|
void dd_process (void);
|
||||||
|
|
||||||
|
|
||||||
|
@ -9,15 +9,15 @@
|
|||||||
#define FLASHRAM_BUFFER_ADDRESS (0x05002900UL)
|
#define FLASHRAM_BUFFER_ADDRESS (0x05002900UL)
|
||||||
|
|
||||||
|
|
||||||
enum operation {
|
typedef enum {
|
||||||
OP_NONE,
|
OP_NONE,
|
||||||
OP_ERASE_ALL,
|
OP_ERASE_ALL,
|
||||||
OP_ERASE_SECTOR,
|
OP_ERASE_SECTOR,
|
||||||
OP_WRITE_PAGE
|
OP_WRITE_PAGE
|
||||||
};
|
} flashram_op_t;
|
||||||
|
|
||||||
|
|
||||||
static enum operation flashram_operation_type (uint32_t scr) {
|
static flashram_op_t flashram_operation_type (uint32_t scr) {
|
||||||
if (!(scr & FLASHRAM_SCR_PENDING)) {
|
if (!(scr & FLASHRAM_SCR_PENDING)) {
|
||||||
return OP_NONE;
|
return OP_NONE;
|
||||||
}
|
}
|
||||||
@ -40,40 +40,47 @@ void flashram_init (void) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void flashram_process (void) {
|
void flashram_process (void) {
|
||||||
uint32_t scr = fpga_reg_get(REG_FLASHRAM_SCR);
|
uint32_t scr = fpga_reg_get(REG_FLASHRAM_SCR);
|
||||||
enum operation op = flashram_operation_type(scr);
|
|
||||||
uint8_t read_buffer[FLASHRAM_PAGE_SIZE];
|
|
||||||
uint8_t write_buffer[FLASHRAM_PAGE_SIZE];
|
|
||||||
uint32_t address = FLASHRAM_ADDRESS;
|
|
||||||
uint32_t erase_size = (op == OP_ERASE_SECTOR) ? FLASHRAM_SECTOR_SIZE : FLASHRAM_SIZE;
|
|
||||||
uint32_t page = (op != OP_ERASE_ALL) ? ((scr & FLASHRAM_SCR_PAGE_MASK) >> FLASHRAM_SCR_PAGE_BIT) : 0;
|
|
||||||
address += page * FLASHRAM_PAGE_SIZE;
|
|
||||||
|
|
||||||
switch (op) {
|
flashram_op_t op = flashram_operation_type(scr);
|
||||||
case OP_ERASE_ALL:
|
|
||||||
case OP_ERASE_SECTOR:
|
|
||||||
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:
|
if (op == OP_NONE) {
|
||||||
fpga_mem_read(FLASHRAM_BUFFER_ADDRESS, FLASHRAM_PAGE_SIZE, read_buffer);
|
return;
|
||||||
fpga_mem_read(address, FLASHRAM_PAGE_SIZE, write_buffer);
|
|
||||||
for (int i = 0; i < FLASHRAM_PAGE_SIZE; i++) {
|
|
||||||
write_buffer[i] &= read_buffer[i];
|
|
||||||
}
|
|
||||||
fpga_mem_write(address, FLASHRAM_PAGE_SIZE, write_buffer);
|
|
||||||
fpga_reg_set(REG_FLASHRAM_SCR, FLASHRAM_SCR_DONE);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case OP_NONE:
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
page &= ~((FLASHRAM_SECTOR_SIZE / FLASHRAM_PAGE_SIZE) - 1);
|
||||||
|
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
|
|
||||||
void flashram_init (void);
|
void flashram_init (void);
|
||||||
|
|
||||||
void flashram_process (void);
|
void flashram_process (void);
|
||||||
|
|
||||||
|
|
||||||
|
@ -7,8 +7,8 @@ uint8_t fpga_id_get (void) {
|
|||||||
uint8_t id;
|
uint8_t id;
|
||||||
|
|
||||||
hw_spi_start();
|
hw_spi_start();
|
||||||
hw_spi_trx((uint8_t *) (&cmd), 1, SPI_TX);
|
hw_spi_tx((uint8_t *) (&cmd), 1);
|
||||||
hw_spi_trx(&id, 1, SPI_RX);
|
hw_spi_rx(&id, 1);
|
||||||
hw_spi_stop();
|
hw_spi_stop();
|
||||||
|
|
||||||
return id;
|
return id;
|
||||||
@ -19,9 +19,9 @@ uint32_t fpga_reg_get (fpga_reg_t reg) {
|
|||||||
uint32_t value;
|
uint32_t value;
|
||||||
|
|
||||||
hw_spi_start();
|
hw_spi_start();
|
||||||
hw_spi_trx((uint8_t *) (&cmd), 1, SPI_TX);
|
hw_spi_tx((uint8_t *) (&cmd), 1);
|
||||||
hw_spi_trx(®, 1, SPI_TX);
|
hw_spi_tx(®, 1);
|
||||||
hw_spi_trx((uint8_t *) (&value), 4, SPI_RX);
|
hw_spi_rx((uint8_t *) (&value), 4);
|
||||||
hw_spi_stop();
|
hw_spi_stop();
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
@ -31,9 +31,9 @@ void fpga_reg_set (fpga_reg_t reg, uint32_t value) {
|
|||||||
fpga_cmd_t cmd = CMD_REG_WRITE;
|
fpga_cmd_t cmd = CMD_REG_WRITE;
|
||||||
|
|
||||||
hw_spi_start();
|
hw_spi_start();
|
||||||
hw_spi_trx((uint8_t *) (&cmd), 1, SPI_TX);
|
hw_spi_tx((uint8_t *) (&cmd), 1);
|
||||||
hw_spi_trx(®, 1, SPI_TX);
|
hw_spi_tx(®, 1);
|
||||||
hw_spi_trx((uint8_t *) (&value), 4, SPI_TX);
|
hw_spi_tx((uint8_t *) (&value), 4);
|
||||||
hw_spi_stop();
|
hw_spi_stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -50,9 +50,9 @@ void fpga_mem_read (uint32_t address, size_t length, uint8_t *buffer) {
|
|||||||
while (fpga_reg_get(REG_MEM_SCR) & MEM_SCR_BUSY);
|
while (fpga_reg_get(REG_MEM_SCR) & MEM_SCR_BUSY);
|
||||||
|
|
||||||
hw_spi_start();
|
hw_spi_start();
|
||||||
hw_spi_trx((uint8_t *) (&cmd), 1, SPI_TX);
|
hw_spi_tx((uint8_t *) (&cmd), 1);
|
||||||
hw_spi_trx(&buffer_address, 1, SPI_TX);
|
hw_spi_tx(&buffer_address, 1);
|
||||||
hw_spi_trx(buffer, length, SPI_RX);
|
hw_spi_rx(buffer, length);
|
||||||
hw_spi_stop();
|
hw_spi_stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,9 +65,9 @@ void fpga_mem_write (uint32_t address, size_t length, uint8_t *buffer) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
hw_spi_start();
|
hw_spi_start();
|
||||||
hw_spi_trx((uint8_t *) (&cmd), 1, SPI_TX);
|
hw_spi_tx((uint8_t *) (&cmd), 1);
|
||||||
hw_spi_trx(&buffer_address, 1, SPI_TX);
|
hw_spi_tx(&buffer_address, 1);
|
||||||
hw_spi_trx(buffer, length, SPI_TX);
|
hw_spi_tx(buffer, length);
|
||||||
hw_spi_stop();
|
hw_spi_stop();
|
||||||
|
|
||||||
fpga_reg_set(REG_MEM_ADDRESS, address);
|
fpga_reg_set(REG_MEM_ADDRESS, address);
|
||||||
@ -95,8 +95,8 @@ uint8_t fpga_usb_status_get (void) {
|
|||||||
uint8_t status;
|
uint8_t status;
|
||||||
|
|
||||||
hw_spi_start();
|
hw_spi_start();
|
||||||
hw_spi_trx((uint8_t *) (&cmd), 1, SPI_TX);
|
hw_spi_tx((uint8_t *) (&cmd), 1);
|
||||||
hw_spi_trx(&status, 1, SPI_RX);
|
hw_spi_rx(&status, 1);
|
||||||
hw_spi_stop();
|
hw_spi_stop();
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
@ -107,8 +107,8 @@ uint8_t fpga_usb_pop (void) {
|
|||||||
uint8_t data;
|
uint8_t data;
|
||||||
|
|
||||||
hw_spi_start();
|
hw_spi_start();
|
||||||
hw_spi_trx((uint8_t *) (&cmd), 1, SPI_TX);
|
hw_spi_tx((uint8_t *) (&cmd), 1);
|
||||||
hw_spi_trx(&data, 1, SPI_RX);
|
hw_spi_rx(&data, 1);
|
||||||
hw_spi_stop();
|
hw_spi_stop();
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
@ -118,7 +118,7 @@ void fpga_usb_push (uint8_t data) {
|
|||||||
fpga_cmd_t cmd = CMD_USB_WRITE;
|
fpga_cmd_t cmd = CMD_USB_WRITE;
|
||||||
|
|
||||||
hw_spi_start();
|
hw_spi_start();
|
||||||
hw_spi_trx((uint8_t *) (&cmd), 1, SPI_TX);
|
hw_spi_tx((uint8_t *) (&cmd), 1);
|
||||||
hw_spi_trx(&data, 1, SPI_TX);
|
hw_spi_tx(&data, 1);
|
||||||
hw_spi_stop();
|
hw_spi_stop();
|
||||||
}
|
}
|
||||||
|
@ -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();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,8 +0,0 @@
|
|||||||
#ifndef GVR_H__
|
|
||||||
#define GVR_H__
|
|
||||||
|
|
||||||
|
|
||||||
void gvr_task (void);
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,9 +1,134 @@
|
|||||||
|
#include <stdbool.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stm32g0xx.h>
|
#include <stm32g0xx.h>
|
||||||
#include "hw.h"
|
#include "hw.h"
|
||||||
|
|
||||||
|
|
||||||
#define UART_BAUD (115200)
|
#define CPU_FREQ (64000000UL)
|
||||||
|
|
||||||
|
|
||||||
|
void hw_set_vector_table (uint32_t offset) {
|
||||||
|
SCB->VTOR = (__IOM uint32_t) (offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void hw_enter_critical (void) {
|
||||||
|
__disable_irq();
|
||||||
|
}
|
||||||
|
|
||||||
|
void hw_exit_critical (void) {
|
||||||
|
__enable_irq();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void hw_clock_init (void) {
|
||||||
|
FLASH->ACR |= (FLASH_ACR_PRFTEN | (2 << FLASH_ACR_LATENCY_Pos));
|
||||||
|
while ((FLASH->ACR & FLASH_ACR_LATENCY_Msk) != (2 << FLASH_ACR_LATENCY_Pos));
|
||||||
|
|
||||||
|
RCC->PLLCFGR = (
|
||||||
|
((2 - 1) << RCC_PLLCFGR_PLLR_Pos)
|
||||||
|
| RCC_PLLCFGR_PLLREN
|
||||||
|
| (16 << RCC_PLLCFGR_PLLN_Pos)
|
||||||
|
| ((2 - 1) << RCC_PLLCFGR_PLLM_Pos)
|
||||||
|
| RCC_PLLCFGR_PLLSRC_HSI
|
||||||
|
);
|
||||||
|
|
||||||
|
RCC->CR |= RCC_CR_PLLON;
|
||||||
|
while ((RCC->CR & RCC_CR_PLLRDY_Msk) != RCC_CR_PLLRDY);
|
||||||
|
|
||||||
|
RCC->CFGR = RCC_CFGR_SW_1;
|
||||||
|
while ((RCC->CFGR & RCC_CFGR_SWS_Msk) != RCC_CFGR_SWS_1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#define TIMEOUT_US_PER_TICK (10)
|
||||||
|
|
||||||
|
static void hw_timeout_init (void) {
|
||||||
|
RCC->APBENR1 |= RCC_APBENR1_DBGEN;
|
||||||
|
DBG->APBFZ2 |= DBG_APB_FZ2_DBG_TIM1_STOP;
|
||||||
|
|
||||||
|
RCC->APBENR2 |= RCC_APBENR2_TIM1EN;
|
||||||
|
|
||||||
|
TIM1->CR1 = TIM_CR1_OPM;
|
||||||
|
TIM1->PSC = (((CPU_FREQ / 1000 / 1000) * TIMEOUT_US_PER_TICK) - 1);
|
||||||
|
TIM1->EGR = TIM_EGR_UG;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void hw_timeout_start (void) {
|
||||||
|
TIM1->CR1 &= ~(TIM_CR1_CEN);
|
||||||
|
TIM1->CNT = 0;
|
||||||
|
TIM1->CR1 |= TIM_CR1_CEN;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool hw_timeout_occured (uint32_t timeout_us) {
|
||||||
|
uint16_t count = TIM1->CNT;
|
||||||
|
|
||||||
|
uint32_t adjusted_timeout = ((timeout_us + (TIMEOUT_US_PER_TICK - 1)) / TIMEOUT_US_PER_TICK);
|
||||||
|
|
||||||
|
if ((count >= adjusted_timeout) || (count == 0xFFFF)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#define DELAY_US_PER_TICK (1)
|
||||||
|
#define DELAY_MS_PER_TICK (1)
|
||||||
|
|
||||||
|
static void hw_delay_init (void) {
|
||||||
|
RCC->APBENR1 |= RCC_APBENR1_DBGEN;
|
||||||
|
DBG->APBFZ1 |= DBG_APB_FZ1_DBG_TIM3_STOP;
|
||||||
|
|
||||||
|
RCC->APBENR1 |= RCC_APBENR1_TIM3EN;
|
||||||
|
|
||||||
|
TIM3->CR1 = TIM_CR1_OPM;
|
||||||
|
TIM3->EGR = TIM_EGR_UG;
|
||||||
|
}
|
||||||
|
|
||||||
|
void hw_delay_us (uint32_t delay_us) {
|
||||||
|
TIM3->CR1 &= ~(TIM_CR1_CEN);
|
||||||
|
TIM3->PSC = (((CPU_FREQ / 1000 / 1000) * DELAY_US_PER_TICK) - 1);
|
||||||
|
TIM3->CNT = 0;
|
||||||
|
TIM3->EGR = TIM_EGR_UG;
|
||||||
|
TIM3->CR1 |= TIM_CR1_CEN;
|
||||||
|
|
||||||
|
uint32_t adjusted_delay = ((delay_us + (DELAY_US_PER_TICK - 1)) / DELAY_US_PER_TICK);
|
||||||
|
|
||||||
|
uint16_t count;
|
||||||
|
do {
|
||||||
|
count = TIM3->CNT;
|
||||||
|
} while ((count < adjusted_delay) && (count != 0xFFFF));
|
||||||
|
}
|
||||||
|
|
||||||
|
void hw_delay_ms (uint32_t delay_ms) {
|
||||||
|
TIM3->CR1 &= ~(TIM_CR1_CEN);
|
||||||
|
TIM3->PSC = (((CPU_FREQ / 1000) * DELAY_MS_PER_TICK) - 1);
|
||||||
|
TIM3->CNT = 0;
|
||||||
|
TIM3->EGR = TIM_EGR_UG;
|
||||||
|
TIM3->CR1 |= TIM_CR1_CEN;
|
||||||
|
|
||||||
|
uint32_t adjusted_delay = ((delay_ms + (DELAY_MS_PER_TICK - 1)) / DELAY_MS_PER_TICK);
|
||||||
|
|
||||||
|
uint16_t count;
|
||||||
|
do {
|
||||||
|
count = TIM3->CNT;
|
||||||
|
} while ((count < adjusted_delay) && (count != 0xFFFF));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void (*systick_callback) (void) = NULL;
|
||||||
|
|
||||||
|
void hw_systick_config (uint32_t period_ms, void (*callback) (void)) {
|
||||||
|
SysTick_Config((CPU_FREQ / 1000) * period_ms);
|
||||||
|
systick_callback = callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SysTick_Handler (void) {
|
||||||
|
if (systick_callback) {
|
||||||
|
systick_callback();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
@ -42,22 +167,7 @@ typedef enum {
|
|||||||
GPIO_AF_7 = 0x07
|
GPIO_AF_7 = 0x07
|
||||||
} gpio_af_t;
|
} gpio_af_t;
|
||||||
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
void (*volatile falling)(void);
|
|
||||||
void (*volatile rising)(void);
|
|
||||||
} gpio_irq_callback_t;
|
|
||||||
|
|
||||||
|
|
||||||
static const GPIO_TypeDef *gpios[] = { GPIOA, GPIOB, 0, 0, 0, 0, 0, 0 };
|
static const GPIO_TypeDef *gpios[] = { GPIOA, GPIOB, 0, 0, 0, 0, 0, 0 };
|
||||||
static gpio_irq_callback_t gpio_irq_callbacks[16];
|
|
||||||
static volatile uint8_t *i2c_data_txptr;
|
|
||||||
static volatile uint8_t *i2c_data_rxptr;
|
|
||||||
static volatile uint32_t i2c_next_cr2;
|
|
||||||
static void (*volatile i2c_callback)(void);
|
|
||||||
static const TIM_TypeDef *tims[] = { TIM14, TIM16, TIM17, TIM3, TIM1 };
|
|
||||||
static void (*volatile tim_callbacks[5])(void);
|
|
||||||
|
|
||||||
|
|
||||||
static void hw_gpio_init (gpio_id_t id, gpio_mode_t mode, gpio_ot_t ot, gpio_ospeed_t ospeed, gpio_pupd_t pupd, gpio_af_t af, int value) {
|
static void hw_gpio_init (gpio_id_t id, gpio_mode_t mode, gpio_ot_t ot, gpio_ospeed_t ospeed, gpio_pupd_t pupd, gpio_af_t af, int value) {
|
||||||
GPIO_TypeDef tmp;
|
GPIO_TypeDef tmp;
|
||||||
@ -65,6 +175,8 @@ static void hw_gpio_init (gpio_id_t id, gpio_mode_t mode, gpio_ot_t ot, gpio_osp
|
|||||||
uint8_t pin = (id & 0x0F);
|
uint8_t pin = (id & 0x0F);
|
||||||
uint8_t afr = ((pin < 8) ? 0 : 1);
|
uint8_t afr = ((pin < 8) ? 0 : 1);
|
||||||
|
|
||||||
|
RCC->IOPENR |= (RCC_IOPENR_GPIOAEN | RCC_IOPENR_GPIOBEN);
|
||||||
|
|
||||||
tmp.MODER = (gpio->MODER & ~(GPIO_MODER_MODE0_Msk << (pin * 2)));
|
tmp.MODER = (gpio->MODER & ~(GPIO_MODER_MODE0_Msk << (pin * 2)));
|
||||||
tmp.OTYPER = (gpio->OTYPER & ~(GPIO_OTYPER_OT0_Msk << pin));
|
tmp.OTYPER = (gpio->OTYPER & ~(GPIO_OTYPER_OT0_Msk << pin));
|
||||||
tmp.OSPEEDR = (gpio->OSPEEDR & ~(GPIO_OSPEEDR_OSPEED0_Msk << (pin * 2)));
|
tmp.OSPEEDR = (gpio->OSPEEDR & ~(GPIO_OSPEEDR_OSPEED0_Msk << (pin * 2)));
|
||||||
@ -80,22 +192,6 @@ static void hw_gpio_init (gpio_id_t id, gpio_mode_t mode, gpio_ot_t ot, gpio_osp
|
|||||||
gpio->MODER = (tmp.MODER | (mode << (pin * 2)));
|
gpio->MODER = (tmp.MODER | (mode << (pin * 2)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void hw_gpio_irq_setup (gpio_id_t id, gpio_irq_t irq, void (*callback)(void)) {
|
|
||||||
uint8_t port = ((id >> 4) & 0x07);
|
|
||||||
uint8_t pin = (id & 0x0F);
|
|
||||||
__disable_irq();
|
|
||||||
if (irq == GPIO_IRQ_FALLING) {
|
|
||||||
EXTI->FTSR1 |= (EXTI_FTSR1_FT0 << pin);
|
|
||||||
gpio_irq_callbacks[pin].falling = callback;
|
|
||||||
} else {
|
|
||||||
EXTI->RTSR1 |= (EXTI_RTSR1_RT0 << pin);
|
|
||||||
gpio_irq_callbacks[pin].rising = callback;
|
|
||||||
}
|
|
||||||
EXTI->EXTICR[pin / 4] |= (port << (8 * (pin % 4)));
|
|
||||||
EXTI->IMR1 |= (EXTI_IMR1_IM0 << pin);
|
|
||||||
__enable_irq();
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t hw_gpio_get (gpio_id_t id) {
|
uint32_t hw_gpio_get (gpio_id_t id) {
|
||||||
GPIO_TypeDef *gpio = ((GPIO_TypeDef *) (gpios[(id >> 4) & 0x07]));
|
GPIO_TypeDef *gpio = ((GPIO_TypeDef *) (gpios[(id >> 4) & 0x07]));
|
||||||
uint8_t pin = (id & 0x0F);
|
uint8_t pin = (id & 0x0F);
|
||||||
@ -114,6 +210,22 @@ void hw_gpio_reset (gpio_id_t id) {
|
|||||||
gpio->BSRR = (GPIO_BSRR_BR0 << pin);
|
gpio->BSRR = (GPIO_BSRR_BR0 << pin);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#define UART_BAUD (115200UL)
|
||||||
|
|
||||||
|
static void hw_uart_init (void) {
|
||||||
|
RCC->APBENR2 |= (RCC_APBENR2_USART1EN | RCC_APBENR2_SYSCFGEN);
|
||||||
|
|
||||||
|
SYSCFG->CFGR1 |= (SYSCFG_CFGR1_PA12_RMP | SYSCFG_CFGR1_PA11_RMP);
|
||||||
|
|
||||||
|
hw_gpio_init(GPIO_ID_UART_TX, GPIO_ALT, GPIO_PP, GPIO_SPEED_LOW, GPIO_PULL_UP, GPIO_AF_1, 0);
|
||||||
|
hw_gpio_init(GPIO_ID_UART_RX, GPIO_ALT, GPIO_PP, GPIO_SPEED_LOW, GPIO_PULL_UP, GPIO_AF_1, 0);
|
||||||
|
|
||||||
|
USART1->BRR = (CPU_FREQ / UART_BAUD);
|
||||||
|
USART1->RQR = (USART_RQR_TXFRQ | USART_RQR_RXFRQ);
|
||||||
|
USART1->CR1 = (USART_CR1_FIFOEN | USART_CR1_M0 | USART_CR1_PCE | USART_CR1_TE | USART_CR1_RE | USART_CR1_UE);
|
||||||
|
}
|
||||||
|
|
||||||
void hw_uart_read (uint8_t *data, int length) {
|
void hw_uart_read (uint8_t *data, int length) {
|
||||||
for (int i = 0; i < length; i++) {
|
for (int i = 0; i < length; i++) {
|
||||||
while (!(USART1->ISR & USART_ISR_RXNE_RXFNE));
|
while (!(USART1->ISR & USART_ISR_RXNE_RXFNE));
|
||||||
@ -128,10 +240,42 @@ void hw_uart_write (uint8_t *data, int length) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void hw_uart_wait_busy (void) {
|
void hw_uart_write_wait_busy (void) {
|
||||||
while (!(USART1->ISR & USART_ISR_TC));
|
while (!(USART1->ISR & USART_ISR_TC));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void hw_spi_init (void) {
|
||||||
|
RCC->AHBENR |= RCC_AHBENR_DMA1EN;
|
||||||
|
RCC->APBENR2 |= RCC_APBENR2_SPI1EN;
|
||||||
|
|
||||||
|
DMAMUX1_Channel0->CCR = (16 << DMAMUX_CxCR_DMAREQ_ID_Pos);
|
||||||
|
DMAMUX1_Channel1->CCR = (17 << DMAMUX_CxCR_DMAREQ_ID_Pos);
|
||||||
|
|
||||||
|
DMA1_Channel1->CPAR = (uint32_t) (&SPI1->DR);
|
||||||
|
DMA1_Channel2->CPAR = (uint32_t) (&SPI1->DR);
|
||||||
|
|
||||||
|
SPI1->CR2 = (
|
||||||
|
SPI_CR2_FRXTH |
|
||||||
|
(8 - 1) << SPI_CR2_DS_Pos |
|
||||||
|
SPI_CR2_TXDMAEN |
|
||||||
|
SPI_CR2_RXDMAEN
|
||||||
|
);
|
||||||
|
SPI1->CR1 = (
|
||||||
|
SPI_CR1_SSM |
|
||||||
|
SPI_CR1_SSI |
|
||||||
|
SPI_CR1_BR_1 |
|
||||||
|
SPI_CR1_SPE |
|
||||||
|
SPI_CR1_MSTR |
|
||||||
|
SPI_CR1_CPHA
|
||||||
|
);
|
||||||
|
|
||||||
|
hw_gpio_init(GPIO_ID_SPI_CS, GPIO_OUTPUT, GPIO_PP, GPIO_SPEED_HIGH, GPIO_PULL_NONE, GPIO_AF_0, 1);
|
||||||
|
hw_gpio_init(GPIO_ID_SPI_CLK, GPIO_ALT, GPIO_PP, GPIO_SPEED_HIGH, GPIO_PULL_NONE, GPIO_AF_0, 0);
|
||||||
|
hw_gpio_init(GPIO_ID_SPI_MOSI, GPIO_ALT, GPIO_PP, GPIO_SPEED_HIGH, GPIO_PULL_NONE, GPIO_AF_0, 0);
|
||||||
|
hw_gpio_init(GPIO_ID_SPI_MISO, GPIO_ALT, GPIO_PP, GPIO_SPEED_HIGH, GPIO_PULL_DOWN, GPIO_AF_0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
void hw_spi_start (void) {
|
void hw_spi_start (void) {
|
||||||
hw_gpio_reset(GPIO_ID_SPI_CS);
|
hw_gpio_reset(GPIO_ID_SPI_CS);
|
||||||
}
|
}
|
||||||
@ -141,186 +285,149 @@ void hw_spi_stop (void) {
|
|||||||
hw_gpio_set(GPIO_ID_SPI_CS);
|
hw_gpio_set(GPIO_ID_SPI_CS);
|
||||||
}
|
}
|
||||||
|
|
||||||
void hw_spi_trx (uint8_t *data, int length, spi_direction_t direction) {
|
void hw_spi_rx (uint8_t *data, int length) {
|
||||||
|
volatile uint8_t dummy = 0x00;
|
||||||
|
|
||||||
|
DMA1_Channel1->CNDTR = length;
|
||||||
|
DMA1_Channel2->CNDTR = length;
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
DMA1_Channel1->CCR = 0;
|
||||||
|
DMA1_Channel2->CCR = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void hw_spi_tx (uint8_t *data, int length) {
|
||||||
volatile uint8_t dummy __attribute__((unused));
|
volatile uint8_t dummy __attribute__((unused));
|
||||||
|
|
||||||
DMA1_Channel1->CNDTR = length;
|
DMA1_Channel1->CNDTR = length;
|
||||||
DMA1_Channel2->CNDTR = length;
|
DMA1_Channel2->CNDTR = length;
|
||||||
|
|
||||||
if (direction == SPI_TX) {
|
DMA1_Channel1->CMAR = (uint32_t) (&dummy);
|
||||||
DMA1_Channel1->CMAR = (uint32_t) (&dummy);
|
DMA1_Channel1->CCR = DMA_CCR_EN;
|
||||||
DMA1_Channel1->CCR = DMA_CCR_EN;
|
|
||||||
|
|
||||||
DMA1_Channel2->CMAR = (uint32_t) (data);
|
DMA1_Channel2->CMAR = (uint32_t) (data);
|
||||||
DMA1_Channel2->CCR = (DMA_CCR_MINC | DMA_CCR_DIR | DMA_CCR_EN);
|
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);
|
while (DMA1_Channel1->CNDTR || DMA1_Channel2->CNDTR);
|
||||||
|
|
||||||
DMA1_Channel1->CCR = 0;
|
DMA1_Channel1->CCR = 0;
|
||||||
DMA1_Channel2->CCR = 0;
|
DMA1_Channel2->CCR = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void hw_i2c_read (uint8_t i2c_address, uint8_t address, uint8_t *data, uint8_t length, void (*callback)(void)) {
|
|
||||||
i2c_data_rxptr = data;
|
#define I2C_TIMEOUT_US_BUSY (10000)
|
||||||
i2c_callback = callback;
|
#define I2C_TIMEOUT_US_PER_BYTE (1000)
|
||||||
I2C1->TXDR = address;
|
|
||||||
i2c_next_cr2 = (
|
static void hw_i2c_init (void) {
|
||||||
I2C_CR2_AUTOEND |
|
RCC->APBENR1 |= RCC_APBENR1_I2C1EN;
|
||||||
(length << I2C_CR2_NBYTES_Pos) |
|
|
||||||
I2C_CR2_START |
|
I2C1->CR1 = 0;
|
||||||
I2C_CR2_RD_WRN |
|
|
||||||
(i2c_address << I2C_CR2_SADD_Pos)
|
hw_gpio_init(GPIO_ID_I2C_SCL, GPIO_ALT, GPIO_OD, GPIO_SPEED_VLOW, GPIO_PULL_NONE, GPIO_AF_6, 0);
|
||||||
);
|
hw_gpio_init(GPIO_ID_I2C_SDA, GPIO_ALT, GPIO_OD, GPIO_SPEED_VLOW, GPIO_PULL_NONE, GPIO_AF_6, 0);
|
||||||
I2C1->CR2 = (
|
|
||||||
(1 << I2C_CR2_NBYTES_Pos) |
|
while (!(hw_gpio_get(GPIO_ID_I2C_SCL) && hw_gpio_get(GPIO_ID_I2C_SDA)));
|
||||||
I2C_CR2_START |
|
|
||||||
(i2c_address << I2C_CR2_SADD_Pos)
|
I2C1->TIMINGR = 0x10901032UL;
|
||||||
);
|
I2C1->CR1 |= I2C_CR1_PE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void hw_i2c_write (uint8_t i2c_address, uint8_t address, uint8_t *data, uint8_t length, void (*callback)(void)) {
|
i2c_err_t hw_i2c_trx (uint8_t address, uint8_t *tx_data, uint8_t tx_length, uint8_t *rx_data, uint8_t rx_length) {
|
||||||
i2c_data_txptr = data;
|
hw_timeout_start();
|
||||||
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)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t hw_i2c_get_error (void) {
|
while (I2C1->ISR & I2C_ISR_BUSY) {
|
||||||
return (I2C1->ISR & I2C_ISR_NACKF);
|
if (hw_timeout_occured(I2C_TIMEOUT_US_BUSY)) {
|
||||||
}
|
return I2C_ERR_BUSY;
|
||||||
|
}
|
||||||
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);
|
|
||||||
|
|
||||||
if (tx_length > 0) {
|
if (tx_length > 0) {
|
||||||
|
uint32_t tx_timeout = ((tx_length + 1) * I2C_TIMEOUT_US_PER_BYTE);
|
||||||
|
|
||||||
|
hw_timeout_start();
|
||||||
|
|
||||||
I2C1->ICR = I2C_ICR_NACKCF;
|
I2C1->ICR = I2C_ICR_NACKCF;
|
||||||
I2C1->CR2 = (
|
I2C1->CR2 = (
|
||||||
((rx_length == 0) ? I2C_CR2_AUTOEND : 0) |
|
((rx_length > 0) ? 0 : I2C_CR2_AUTOEND) |
|
||||||
(tx_length << I2C_CR2_NBYTES_Pos) |
|
(tx_length << I2C_CR2_NBYTES_Pos) |
|
||||||
I2C_CR2_START |
|
I2C_CR2_START |
|
||||||
(i2c_address << I2C_CR2_SADD_Pos)
|
(address << I2C_CR2_SADD_Pos)
|
||||||
);
|
);
|
||||||
for (int i = 0; i < tx_length; i++) {
|
|
||||||
while (!(I2C1->ISR & I2C_ISR_TXIS));
|
uint8_t left = tx_length;
|
||||||
I2C1->TXDR = *tx_data++;
|
|
||||||
|
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 (!(I2C1->CR2 & I2C_CR2_AUTOEND)) {
|
|
||||||
while (!(I2C1->ISR & (I2C_ISR_NACKF | I2C_ISR_TC)));
|
if (rx_length == 0) {
|
||||||
|
return I2C_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (!(I2C1->ISR & I2C_ISR_TC)) {
|
||||||
|
if (hw_timeout_occured(tx_timeout)) {
|
||||||
|
return I2C_ERR_TIMEOUT;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rx_length > 0) {
|
if (rx_length > 0) {
|
||||||
|
uint32_t rx_timeout = ((rx_length + 1) * I2C_TIMEOUT_US_PER_BYTE);
|
||||||
|
|
||||||
|
hw_timeout_start();
|
||||||
|
|
||||||
I2C1->CR2 = (
|
I2C1->CR2 = (
|
||||||
I2C_CR2_AUTOEND |
|
I2C_CR2_AUTOEND |
|
||||||
(rx_length << I2C_CR2_NBYTES_Pos) |
|
(rx_length << I2C_CR2_NBYTES_Pos) |
|
||||||
I2C_CR2_START |
|
I2C_CR2_START |
|
||||||
I2C_CR2_RD_WRN |
|
I2C_CR2_RD_WRN |
|
||||||
(i2c_address << I2C_CR2_SADD_Pos)
|
(address << I2C_CR2_SADD_Pos)
|
||||||
);
|
);
|
||||||
for (int i = 0; i < rx_length; i++) {
|
|
||||||
while (!(I2C1->ISR & I2C_ISR_RXNE));
|
uint8_t left = rx_length;
|
||||||
*rx_data++ = I2C1->RXDR;
|
|
||||||
|
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)) {
|
return I2C_OK;
|
||||||
while (!(I2C1->ISR & I2C_ISR_STOPF));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void hw_i2c_disable_irq (void) {
|
|
||||||
NVIC_DisableIRQ(I2C1_IRQn);
|
|
||||||
}
|
|
||||||
|
|
||||||
void hw_i2c_enable_irq (void) {
|
static void hw_crc32_init (void) {
|
||||||
NVIC_EnableIRQ(I2C1_IRQn);
|
RCC->AHBENR |= RCC_AHBENR_CRCEN;
|
||||||
}
|
|
||||||
|
|
||||||
void hw_tim_setup (tim_id_t id, uint16_t delay, void (*callback)(void)) {
|
CRC->CR = (CRC_CR_REV_OUT | CRC_CR_REV_IN_0);
|
||||||
if (delay == 0) {
|
|
||||||
if (callback) {
|
|
||||||
callback();
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
TIM_TypeDef *tim = ((TIM_TypeDef *) (tims[id]));
|
|
||||||
tim->CR1 = (TIM_CR1_OPM | TIM_CR1_URS);
|
|
||||||
tim->PSC = (64000 - 1);
|
|
||||||
tim->ARR = delay;
|
|
||||||
tim->DIER = TIM_DIER_UIE;
|
|
||||||
tim->EGR = TIM_EGR_UG;
|
|
||||||
tim->SR = 0;
|
|
||||||
tim->CR1 |= TIM_CR1_CEN;
|
|
||||||
tim_callbacks[id] = callback;
|
|
||||||
}
|
|
||||||
|
|
||||||
void hw_tim_stop (tim_id_t id) {
|
|
||||||
TIM_TypeDef *tim = ((TIM_TypeDef *) (tims[id]));
|
|
||||||
tim->CR1 &= ~(TIM_CR1_CEN);
|
|
||||||
tim_callbacks[id] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void hw_tim_disable_irq (tim_id_t id) {
|
|
||||||
switch (id) {
|
|
||||||
case TIM_ID_CIC:
|
|
||||||
NVIC_DisableIRQ(TIM14_IRQn);
|
|
||||||
break;
|
|
||||||
case TIM_ID_RTC:
|
|
||||||
NVIC_DisableIRQ(TIM16_IRQn);
|
|
||||||
break;
|
|
||||||
case TIM_ID_SD:
|
|
||||||
NVIC_DisableIRQ(TIM17_IRQn);
|
|
||||||
break;
|
|
||||||
case TIM_ID_DD:
|
|
||||||
NVIC_DisableIRQ(TIM3_IRQn);
|
|
||||||
break;
|
|
||||||
case TIM_ID_LED:
|
|
||||||
NVIC_DisableIRQ(TIM1_BRK_UP_TRG_COM_IRQn);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void hw_tim_enable_irq (tim_id_t id) {
|
|
||||||
switch (id) {
|
|
||||||
case TIM_ID_CIC:
|
|
||||||
NVIC_EnableIRQ(TIM14_IRQn);
|
|
||||||
break;
|
|
||||||
case TIM_ID_RTC:
|
|
||||||
NVIC_EnableIRQ(TIM16_IRQn);
|
|
||||||
break;
|
|
||||||
case TIM_ID_SD:
|
|
||||||
NVIC_EnableIRQ(TIM17_IRQn);
|
|
||||||
break;
|
|
||||||
case TIM_ID_DD:
|
|
||||||
NVIC_EnableIRQ(TIM3_IRQn);
|
|
||||||
break;
|
|
||||||
case TIM_ID_LED:
|
|
||||||
NVIC_EnableIRQ(TIM1_BRK_UP_TRG_COM_IRQn);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void hw_delay_ms (uint32_t ms) {
|
|
||||||
SysTick->VAL = 0;
|
|
||||||
for (uint32_t i = 0; i < ms; i++) {
|
|
||||||
while (!(SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void hw_crc32_reset (void) {
|
void hw_crc32_reset (void) {
|
||||||
@ -334,10 +441,15 @@ uint32_t hw_crc32_calculate (uint8_t *data, uint32_t length) {
|
|||||||
return (CRC->DR ^ 0xFFFFFFFF);
|
return (CRC->DR ^ 0xFFFFFFFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
uint32_t hw_flash_size (void) {
|
uint32_t hw_flash_size (void) {
|
||||||
return FLASH_SIZE;
|
return FLASH_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hw_flash_t hw_flash_read (uint32_t offset) {
|
||||||
|
return *(uint64_t *) (FLASH_BASE + offset);
|
||||||
|
}
|
||||||
|
|
||||||
static void hw_flash_unlock (void) {
|
static void hw_flash_unlock (void) {
|
||||||
while (FLASH->SR & FLASH_SR_BSY1);
|
while (FLASH->SR & FLASH_SR_BSY1);
|
||||||
if (FLASH->CR & FLASH_CR_LOCK) {
|
if (FLASH->CR & FLASH_CR_LOCK) {
|
||||||
@ -363,13 +475,10 @@ void hw_flash_program (uint32_t offset, hw_flash_t value) {
|
|||||||
FLASH->CR &= ~(FLASH_CR_PG);
|
FLASH->CR &= ~(FLASH_CR_PG);
|
||||||
}
|
}
|
||||||
|
|
||||||
hw_flash_t hw_flash_read (uint32_t offset) {
|
|
||||||
return *(uint64_t *) (FLASH_BASE + offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
void hw_reset (loader_parameters_t *parameters) {
|
void hw_reset (loader_parameters_t *parameters) {
|
||||||
if (parameters != NULL) {
|
if (parameters != NULL) {
|
||||||
RCC->APBENR1 |= RCC_APBENR1_PWREN | RCC_APBENR1_RTCAPBEN;
|
RCC->APBENR1 |= (RCC_APBENR1_PWREN | RCC_APBENR1_RTCAPBEN);
|
||||||
PWR->CR1 |= PWR_CR1_DBP;
|
PWR->CR1 |= PWR_CR1_DBP;
|
||||||
TAMP->BKP0R = parameters->magic;
|
TAMP->BKP0R = parameters->magic;
|
||||||
TAMP->BKP1R = parameters->flags;
|
TAMP->BKP1R = parameters->flags;
|
||||||
@ -382,8 +491,9 @@ void hw_reset (loader_parameters_t *parameters) {
|
|||||||
NVIC_SystemReset();
|
NVIC_SystemReset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void hw_loader_get_parameters (loader_parameters_t *parameters) {
|
void hw_loader_get_parameters (loader_parameters_t *parameters) {
|
||||||
RCC->APBENR1 |= RCC_APBENR1_PWREN | RCC_APBENR1_RTCAPBEN;
|
RCC->APBENR1 |= (RCC_APBENR1_PWREN | RCC_APBENR1_RTCAPBEN);
|
||||||
parameters->magic = TAMP->BKP0R;
|
parameters->magic = TAMP->BKP0R;
|
||||||
parameters->flags = TAMP->BKP1R;
|
parameters->flags = TAMP->BKP1R;
|
||||||
parameters->mcu_address = TAMP->BKP2R;
|
parameters->mcu_address = TAMP->BKP2R;
|
||||||
@ -399,280 +509,104 @@ void hw_loader_get_parameters (loader_parameters_t *parameters) {
|
|||||||
RCC->APBENR1 &= ~(RCC_APBENR1_PWREN | RCC_APBENR1_RTCAPBEN);
|
RCC->APBENR1 &= ~(RCC_APBENR1_PWREN | RCC_APBENR1_RTCAPBEN);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void hw_init_mcu (void) {
|
|
||||||
FLASH->ACR |= (FLASH_ACR_PRFTEN | (2 << FLASH_ACR_LATENCY_Pos));
|
|
||||||
while ((FLASH->ACR & FLASH_ACR_LATENCY_Msk) != (2 << FLASH_ACR_LATENCY_Pos));
|
|
||||||
|
|
||||||
RCC->PLLCFGR = (
|
#define ADC_VREF_CAL_POINT (3000)
|
||||||
((2 - 1) << RCC_PLLCFGR_PLLR_Pos)
|
#define ADC_VREF_CAL_VALUE (*(uint16_t *) (0x1FFF75AAUL))
|
||||||
| RCC_PLLCFGR_PLLREN
|
|
||||||
| (16 << RCC_PLLCFGR_PLLN_Pos)
|
|
||||||
| ((2 - 1) << RCC_PLLCFGR_PLLM_Pos)
|
|
||||||
| RCC_PLLCFGR_PLLSRC_HSI
|
|
||||||
);
|
|
||||||
|
|
||||||
RCC->CR |= RCC_CR_PLLON;
|
#define TEMP_CAL_POINT_1 (30)
|
||||||
while ((RCC->CR & RCC_CR_PLLRDY_Msk) != RCC_CR_PLLRDY);
|
#define TEMP_CAL_VALUE_1 (*(uint16_t *) (0x1FFF75A8UL))
|
||||||
|
|
||||||
RCC->CFGR = RCC_CFGR_SW_1;
|
#define TEMP_CAL_POINT_2 (130)
|
||||||
while ((RCC->CFGR & RCC_CFGR_SWS_Msk) != RCC_CFGR_SWS_1);
|
#define TEMP_CAL_VALUE_2 (*(uint16_t *) (0x1FFF75CAUL))
|
||||||
|
|
||||||
RCC->IOPENR |= RCC_IOPENR_GPIOAEN | RCC_IOPENR_GPIOBEN;
|
#define TEMP_CAL_VREF (3000)
|
||||||
|
|
||||||
SysTick->LOAD = (((64000000 / 1000)) - 1);
|
#define TEMP_SCALE (10)
|
||||||
SysTick->VAL = 0;
|
|
||||||
SysTick->CTRL = (SysTick_CTRL_CLKSOURCE_Msk | SysTick_CTRL_ENABLE_Msk);
|
|
||||||
|
|
||||||
|
static void hw_adc_init (void) {
|
||||||
|
RCC->APBENR2 |= RCC_APBENR2_ADCEN;
|
||||||
|
|
||||||
|
ADC1->CFGR2 = ADC_CFGR2_CKMODE_1;
|
||||||
|
|
||||||
|
ADC->CCR = (ADC_CCR_TSEN | ADC_CCR_VREFEN);
|
||||||
|
ADC1->CR = ADC_CR_ADVREGEN;
|
||||||
|
|
||||||
|
hw_delay_us(120);
|
||||||
|
|
||||||
|
ADC1->ISR = ADC_ISR_EOCAL;
|
||||||
|
ADC1->CR |= ADC_CR_ADCAL;
|
||||||
|
while (!(ADC1->ISR & ADC_ISR_EOCAL));
|
||||||
|
|
||||||
|
ADC1->CFGR1 = (ADC_CFGR1_AUTOFF | ADC_CFGR1_WAIT | ADC_CFGR1_SCANDIR);
|
||||||
|
ADC1->CFGR2 |= (ADC_CFGR2_OVSS_2 | ADC_CFGR2_OVSR_1 | ADC_CFGR2_OVSR_0 | ADC_CFGR2_OVSE);
|
||||||
|
ADC1->SMPR = (ADC_SMPR_SMP1_2 | ADC_SMPR_SMP1_1 | ADC_SMPR_SMP1_0);
|
||||||
|
|
||||||
|
ADC1->ISR = ADC_ISR_CCRDY;
|
||||||
|
ADC1->CHSELR = (ADC_CHSELR_CHSEL13 | ADC_CHSELR_CHSEL12);
|
||||||
|
while (!(ADC1->ISR & ADC_ISR_CCRDY));
|
||||||
|
|
||||||
|
ADC1->CR |= ADC_CR_ADEN;
|
||||||
|
}
|
||||||
|
|
||||||
|
void hw_adc_read_voltage_temperature (uint16_t *voltage, int16_t *temperature) {
|
||||||
|
ADC1->CR |= ADC_CR_ADSTART;
|
||||||
|
|
||||||
|
while (!(ADC1->ISR & ADC_ISR_EOC));
|
||||||
|
uint16_t adc_vref = ((ADC_VREF_CAL_POINT * ADC_VREF_CAL_VALUE) / ADC1->DR);
|
||||||
|
|
||||||
|
while (!(ADC1->ISR & ADC_ISR_EOC));
|
||||||
|
int16_t adc_temp = ((ADC1->DR * adc_vref) / TEMP_CAL_VREF);
|
||||||
|
|
||||||
|
*voltage = adc_vref;
|
||||||
|
*temperature = (
|
||||||
|
((adc_temp - TEMP_CAL_VALUE_1) * (TEMP_CAL_POINT_2 - TEMP_CAL_POINT_1) * TEMP_SCALE) /
|
||||||
|
(TEMP_CAL_VALUE_2 - TEMP_CAL_VALUE_1)
|
||||||
|
) + (TEMP_CAL_POINT_1 * TEMP_SCALE);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void hw_led_init (void) {
|
||||||
hw_gpio_init(GPIO_ID_LED, GPIO_OUTPUT, GPIO_PP, GPIO_SPEED_VLOW, GPIO_PULL_NONE, GPIO_AF_0, 0);
|
hw_gpio_init(GPIO_ID_LED, GPIO_OUTPUT, GPIO_PP, GPIO_SPEED_VLOW, GPIO_PULL_NONE, GPIO_AF_0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void hw_init_spi (void) {
|
|
||||||
RCC->AHBENR |= RCC_AHBENR_DMA1EN;
|
|
||||||
RCC->APBENR2 |= RCC_APBENR2_SPI1EN;
|
|
||||||
|
|
||||||
DMAMUX1_Channel0->CCR = (16 << DMAMUX_CxCR_DMAREQ_ID_Pos);
|
static void hw_misc_init (void) {
|
||||||
DMAMUX1_Channel1->CCR = (17 << DMAMUX_CxCR_DMAREQ_ID_Pos);
|
hw_gpio_init(GPIO_ID_N64_RESET, GPIO_INPUT, GPIO_OD, GPIO_SPEED_VLOW, GPIO_PULL_DOWN, GPIO_AF_0, 0);
|
||||||
|
hw_gpio_init(GPIO_ID_N64_CIC_CLK, GPIO_INPUT, GPIO_OD, GPIO_SPEED_VLOW, GPIO_PULL_UP, GPIO_AF_0, 0);
|
||||||
DMA1_Channel1->CPAR = (uint32_t) (&SPI1->DR);
|
|
||||||
DMA1_Channel2->CPAR = (uint32_t) (&SPI1->DR);
|
|
||||||
|
|
||||||
SPI1->CR2 = (
|
|
||||||
SPI_CR2_FRXTH |
|
|
||||||
(8 - 1) << SPI_CR2_DS_Pos |
|
|
||||||
SPI_CR2_TXDMAEN |
|
|
||||||
SPI_CR2_RXDMAEN
|
|
||||||
);
|
|
||||||
SPI1->CR1 = (
|
|
||||||
SPI_CR1_SSM |
|
|
||||||
SPI_CR1_SSI |
|
|
||||||
SPI_CR1_BR_1 |
|
|
||||||
SPI_CR1_SPE |
|
|
||||||
SPI_CR1_MSTR |
|
|
||||||
SPI_CR1_CPHA
|
|
||||||
);
|
|
||||||
|
|
||||||
hw_gpio_init(GPIO_ID_SPI_CS, GPIO_OUTPUT, GPIO_PP, GPIO_SPEED_HIGH, GPIO_PULL_NONE, GPIO_AF_0, 1);
|
|
||||||
hw_gpio_init(GPIO_ID_SPI_CLK, GPIO_ALT, GPIO_PP, GPIO_SPEED_HIGH, GPIO_PULL_NONE, GPIO_AF_0, 0);
|
|
||||||
hw_gpio_init(GPIO_ID_SPI_MISO, GPIO_ALT, GPIO_PP, GPIO_SPEED_HIGH, GPIO_PULL_DOWN, GPIO_AF_0, 0);
|
|
||||||
hw_gpio_init(GPIO_ID_SPI_MOSI, GPIO_ALT, GPIO_PP, GPIO_SPEED_HIGH, GPIO_PULL_NONE, GPIO_AF_0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void hw_init_i2c (void) {
|
|
||||||
RCC->APBENR1 |= RCC_APBENR1_I2C1EN;
|
|
||||||
|
|
||||||
I2C1->TIMINGR = 0x80821B20UL;
|
|
||||||
I2C1->CR1 |= (I2C_CR1_TCIE | I2C_CR1_STOPIE | I2C_CR1_RXIE | I2C_CR1_TXIE | I2C_CR1_PE);
|
|
||||||
|
|
||||||
hw_gpio_init(GPIO_ID_I2C_SCL, GPIO_ALT, GPIO_OD, GPIO_SPEED_VLOW, GPIO_PULL_NONE, GPIO_AF_6, 0);
|
|
||||||
hw_gpio_init(GPIO_ID_I2C_SDA, GPIO_ALT, GPIO_OD, GPIO_SPEED_VLOW, GPIO_PULL_NONE, GPIO_AF_6, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void hw_init_uart (void) {
|
|
||||||
RCC->APBENR2 |= (RCC_APBENR2_USART1EN | RCC_APBENR2_SYSCFGEN);
|
|
||||||
|
|
||||||
SYSCFG->CFGR1 |= (SYSCFG_CFGR1_PA12_RMP | SYSCFG_CFGR1_PA11_RMP);
|
|
||||||
|
|
||||||
hw_gpio_init(GPIO_ID_UART_TX, GPIO_ALT, GPIO_PP, GPIO_SPEED_LOW, GPIO_PULL_UP, GPIO_AF_1, 0);
|
|
||||||
hw_gpio_init(GPIO_ID_UART_RX, GPIO_ALT, GPIO_PP, GPIO_SPEED_LOW, GPIO_PULL_UP, GPIO_AF_1, 0);
|
|
||||||
|
|
||||||
USART1->BRR = (64000000UL) / UART_BAUD;
|
|
||||||
USART1->RQR = USART_RQR_TXFRQ | USART_RQR_RXFRQ;
|
|
||||||
USART1->CR1 = USART_CR1_FIFOEN | USART_CR1_M0 | USART_CR1_PCE | USART_CR1_TE | USART_CR1_RE | USART_CR1_UE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void hw_init_tim (void) {
|
|
||||||
RCC->APBENR1 |= (
|
|
||||||
RCC_APBENR1_DBGEN |
|
|
||||||
RCC_APBENR1_TIM3EN
|
|
||||||
);
|
|
||||||
RCC->APBENR2 |= (
|
|
||||||
RCC_APBENR2_TIM17EN |
|
|
||||||
RCC_APBENR2_TIM16EN |
|
|
||||||
RCC_APBENR2_TIM14EN |
|
|
||||||
RCC_APBENR2_USART1EN |
|
|
||||||
RCC_APBENR2_TIM1EN
|
|
||||||
);
|
|
||||||
|
|
||||||
DBG->APBFZ1 |= DBG_APB_FZ1_DBG_TIM3_STOP;
|
|
||||||
DBG->APBFZ2 |= (
|
|
||||||
DBG_APB_FZ2_DBG_TIM17_STOP |
|
|
||||||
DBG_APB_FZ2_DBG_TIM16_STOP |
|
|
||||||
DBG_APB_FZ2_DBG_TIM14_STOP |
|
|
||||||
DBG_APB_FZ2_DBG_TIM1_STOP
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void hw_init_crc (void) {
|
|
||||||
RCC->AHBENR |= RCC_AHBENR_CRCEN;
|
|
||||||
|
|
||||||
CRC->CR = (CRC_CR_REV_OUT | CRC_CR_REV_IN_0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void hw_init_misc (void) {
|
|
||||||
hw_gpio_init(GPIO_ID_N64_RESET, GPIO_INPUT, GPIO_PP, GPIO_SPEED_VLOW, GPIO_PULL_DOWN, GPIO_AF_0, 0);
|
|
||||||
hw_gpio_init(GPIO_ID_N64_CIC_CLK, GPIO_INPUT, GPIO_PP, GPIO_SPEED_VLOW, GPIO_PULL_UP, GPIO_AF_0, 0);
|
|
||||||
hw_gpio_init(GPIO_ID_N64_CIC_DQ, GPIO_INPUT, GPIO_OD, GPIO_SPEED_VLOW, GPIO_PULL_UP, GPIO_AF_0, 1);
|
hw_gpio_init(GPIO_ID_N64_CIC_DQ, GPIO_INPUT, GPIO_OD, GPIO_SPEED_VLOW, GPIO_PULL_UP, GPIO_AF_0, 1);
|
||||||
hw_gpio_init(GPIO_ID_FPGA_INT, GPIO_INPUT, GPIO_PP, GPIO_SPEED_VLOW, GPIO_PULL_UP, GPIO_AF_0, 0);
|
hw_gpio_init(GPIO_ID_FPGA_INT, GPIO_INPUT, GPIO_OD, GPIO_SPEED_VLOW, GPIO_PULL_UP, GPIO_AF_0, 0);
|
||||||
hw_gpio_init(GPIO_ID_RTC_MFP, GPIO_INPUT, GPIO_PP, GPIO_SPEED_VLOW, GPIO_PULL_UP, GPIO_AF_0, 0);
|
hw_gpio_init(GPIO_ID_RTC_MFP, GPIO_INPUT, GPIO_OD, GPIO_SPEED_VLOW, GPIO_PULL_UP, GPIO_AF_0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void hw_set_vector_table (uint32_t offset) {
|
|
||||||
SCB->VTOR = (__IOM uint32_t) (offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
void hw_init (void) {
|
void hw_primer_init (void) {
|
||||||
hw_init_mcu();
|
hw_clock_init();
|
||||||
hw_init_spi();
|
hw_timeout_init();
|
||||||
hw_init_i2c();
|
hw_delay_init();
|
||||||
hw_init_uart();
|
hw_led_init();
|
||||||
hw_init_tim();
|
hw_uart_init();
|
||||||
hw_init_crc();
|
hw_spi_init();
|
||||||
hw_init_misc();
|
hw_i2c_init();
|
||||||
|
hw_crc32_init();
|
||||||
NVIC_SetPriority(EXTI0_1_IRQn, 0);
|
|
||||||
NVIC_SetPriority(EXTI2_3_IRQn, 0);
|
|
||||||
NVIC_SetPriority(EXTI4_15_IRQn, 0);
|
|
||||||
NVIC_SetPriority(I2C1_IRQn, 0);
|
|
||||||
NVIC_SetPriority(TIM14_IRQn, 0);
|
|
||||||
NVIC_SetPriority(TIM16_IRQn, 0);
|
|
||||||
NVIC_SetPriority(TIM17_IRQn, 0);
|
|
||||||
NVIC_SetPriority(TIM3_IRQn, 0);
|
|
||||||
NVIC_SetPriority(TIM1_BRK_UP_TRG_COM_IRQn, 0);
|
|
||||||
|
|
||||||
NVIC_EnableIRQ(EXTI0_1_IRQn);
|
|
||||||
NVIC_EnableIRQ(EXTI2_3_IRQn);
|
|
||||||
NVIC_EnableIRQ(EXTI4_15_IRQn);
|
|
||||||
NVIC_EnableIRQ(I2C1_IRQn);
|
|
||||||
NVIC_EnableIRQ(TIM14_IRQn);
|
|
||||||
NVIC_EnableIRQ(TIM16_IRQn);
|
|
||||||
NVIC_EnableIRQ(TIM17_IRQn);
|
|
||||||
NVIC_EnableIRQ(TIM3_IRQn);
|
|
||||||
NVIC_EnableIRQ(TIM1_BRK_UP_TRG_COM_IRQn);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void hw_loader_init (void) {
|
void hw_loader_init (void) {
|
||||||
hw_init_mcu();
|
hw_clock_init();
|
||||||
hw_init_spi();
|
hw_timeout_init();
|
||||||
|
hw_delay_init();
|
||||||
|
hw_led_init();
|
||||||
|
hw_spi_init();
|
||||||
}
|
}
|
||||||
|
|
||||||
void hw_primer_init (void) {
|
void hw_app_init (void) {
|
||||||
hw_init_mcu();
|
hw_clock_init();
|
||||||
hw_init_spi();
|
hw_timeout_init();
|
||||||
hw_init_i2c();
|
hw_delay_init();
|
||||||
hw_init_uart();
|
hw_adc_init();
|
||||||
hw_init_crc();
|
hw_led_init();
|
||||||
}
|
hw_misc_init();
|
||||||
|
hw_uart_init();
|
||||||
|
hw_spi_init();
|
||||||
void EXTI0_1_IRQHandler (void) {
|
hw_i2c_init();
|
||||||
for (int i = 0; i <= 1; i++) {
|
hw_crc32_init();
|
||||||
if (EXTI->FPR1 & (EXTI_FPR1_FPIF0 << i)) {
|
|
||||||
EXTI->FPR1 = (EXTI_FPR1_FPIF0 << i);
|
|
||||||
if (gpio_irq_callbacks[i].falling) {
|
|
||||||
gpio_irq_callbacks[i].falling();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (EXTI->RPR1 & (EXTI_RPR1_RPIF0 << i)) {
|
|
||||||
EXTI->RPR1 = (EXTI_RPR1_RPIF0 << i);
|
|
||||||
if (gpio_irq_callbacks[i].rising) {
|
|
||||||
gpio_irq_callbacks[i].rising();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void EXTI2_3_IRQHandler (void) {
|
|
||||||
for (int i = 2; i <= 3; i++) {
|
|
||||||
if (EXTI->FPR1 & (EXTI_FPR1_FPIF0 << i)) {
|
|
||||||
EXTI->FPR1 = (EXTI_FPR1_FPIF0 << i);
|
|
||||||
if (gpio_irq_callbacks[i].falling) {
|
|
||||||
gpio_irq_callbacks[i].falling();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (EXTI->RPR1 & (EXTI_RPR1_RPIF0 << i)) {
|
|
||||||
EXTI->RPR1 = (EXTI_RPR1_RPIF0 << i);
|
|
||||||
if (gpio_irq_callbacks[i].rising) {
|
|
||||||
gpio_irq_callbacks[i].rising();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void EXTI4_15_IRQHandler (void) {
|
|
||||||
for (int i = 4; i <= 15; i++) {
|
|
||||||
if (EXTI->FPR1 & (EXTI_FPR1_FPIF0 << i)) {
|
|
||||||
EXTI->FPR1 = (EXTI_FPR1_FPIF0 << i);
|
|
||||||
if (gpio_irq_callbacks[i].falling) {
|
|
||||||
gpio_irq_callbacks[i].falling();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (EXTI->RPR1 & (EXTI_RPR1_RPIF0 << i)) {
|
|
||||||
EXTI->RPR1 = (EXTI_RPR1_RPIF0 << i);
|
|
||||||
if (gpio_irq_callbacks[i].rising) {
|
|
||||||
gpio_irq_callbacks[i].rising();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void I2C1_IRQHandler (void) {
|
|
||||||
if (I2C1->ISR & I2C_ISR_TXIS) {
|
|
||||||
I2C1->TXDR = *i2c_data_txptr++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (I2C1->ISR & I2C_ISR_RXNE) {
|
|
||||||
*i2c_data_rxptr++ = I2C1->RXDR;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (I2C1->ISR & I2C_ISR_TC) {
|
|
||||||
I2C1->CR2 = i2c_next_cr2;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (I2C1->ISR & I2C_ISR_STOPF) {
|
|
||||||
I2C1->ICR = I2C_ICR_STOPCF;
|
|
||||||
if (i2c_callback) {
|
|
||||||
i2c_callback();
|
|
||||||
i2c_callback = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void TIM14_IRQHandler (void) {
|
|
||||||
TIM14->SR &= ~(TIM_SR_UIF);
|
|
||||||
if (tim_callbacks[0]) {
|
|
||||||
tim_callbacks[0]();
|
|
||||||
tim_callbacks[0] = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void TIM16_IRQHandler (void) {
|
|
||||||
TIM16->SR &= ~(TIM_SR_UIF);
|
|
||||||
if (tim_callbacks[1]) {
|
|
||||||
tim_callbacks[1]();
|
|
||||||
tim_callbacks[1] = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void TIM17_IRQHandler (void) {
|
|
||||||
TIM17->SR &= ~(TIM_SR_UIF);
|
|
||||||
if (tim_callbacks[2]) {
|
|
||||||
tim_callbacks[2]();
|
|
||||||
tim_callbacks[2] = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void TIM3_IRQHandler (void) {
|
|
||||||
TIM3->SR &= ~(TIM_SR_UIF);
|
|
||||||
if (tim_callbacks[3]) {
|
|
||||||
tim_callbacks[3]();
|
|
||||||
tim_callbacks[3] = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void TIM1_BRK_UP_TRG_COM_IRQHandler (void) {
|
|
||||||
TIM1->SR &= ~(TIM_SR_UIF);
|
|
||||||
if (tim_callbacks[4]) {
|
|
||||||
tim_callbacks[4]();
|
|
||||||
tim_callbacks[4] = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
#define GPIO_PORT_PIN(p, n) ((((p) & 0x07) << 4) | ((n) & 0x0F))
|
#define GPIO_PORT_PIN(p, n) ((((p) & 0x07) << 4) | ((n) & 0x0F))
|
||||||
|
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
GPIO_ID_N64_RESET = GPIO_PORT_PIN(0, 0),
|
GPIO_ID_N64_RESET = GPIO_PORT_PIN(0, 0),
|
||||||
GPIO_ID_N64_CIC_CLK = GPIO_PORT_PIN(0, 1),
|
GPIO_ID_N64_CIC_CLK = GPIO_PORT_PIN(0, 1),
|
||||||
@ -25,22 +26,11 @@ typedef enum {
|
|||||||
} gpio_id_t;
|
} gpio_id_t;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
GPIO_IRQ_FALLING = 0b01,
|
I2C_OK,
|
||||||
GPIO_IRQ_RISING = 0b10,
|
I2C_ERR_BUSY,
|
||||||
} gpio_irq_t;
|
I2C_ERR_TIMEOUT,
|
||||||
|
I2C_ERR_NACK,
|
||||||
typedef enum {
|
} i2c_err_t;
|
||||||
TIM_ID_CIC = 0,
|
|
||||||
TIM_ID_RTC = 1,
|
|
||||||
TIM_ID_SD = 2,
|
|
||||||
TIM_ID_DD = 3,
|
|
||||||
TIM_ID_LED = 4,
|
|
||||||
} tim_id_t;
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
SPI_TX,
|
|
||||||
SPI_RX,
|
|
||||||
} spi_direction_t;
|
|
||||||
|
|
||||||
typedef uint64_t hw_flash_t;
|
typedef uint64_t hw_flash_t;
|
||||||
|
|
||||||
@ -59,39 +49,48 @@ typedef struct {
|
|||||||
} loader_parameters_t;
|
} loader_parameters_t;
|
||||||
|
|
||||||
|
|
||||||
void hw_gpio_irq_setup (gpio_id_t id, gpio_irq_t irq, void (*callback)(void));
|
void hw_set_vector_table (uint32_t offset);
|
||||||
|
|
||||||
|
void hw_enter_critical (void);
|
||||||
|
void hw_exit_critical (void);
|
||||||
|
|
||||||
|
void hw_delay_us (uint32_t delay_us);
|
||||||
|
void hw_delay_ms (uint32_t delay_ms);
|
||||||
|
|
||||||
|
void hw_systick_config (uint32_t period_ms, void (*callback) (void));
|
||||||
|
|
||||||
uint32_t hw_gpio_get (gpio_id_t id);
|
uint32_t hw_gpio_get (gpio_id_t id);
|
||||||
void hw_gpio_set (gpio_id_t id);
|
void hw_gpio_set (gpio_id_t id);
|
||||||
void hw_gpio_reset (gpio_id_t id);
|
void hw_gpio_reset (gpio_id_t id);
|
||||||
|
|
||||||
void hw_uart_read (uint8_t *data, int length);
|
void hw_uart_read (uint8_t *data, int length);
|
||||||
void hw_uart_write (uint8_t *data, int length);
|
void hw_uart_write (uint8_t *data, int length);
|
||||||
void hw_uart_wait_busy (void);
|
void hw_uart_write_wait_busy (void);
|
||||||
|
|
||||||
void hw_spi_start (void);
|
void hw_spi_start (void);
|
||||||
void hw_spi_stop (void);
|
void hw_spi_stop (void);
|
||||||
void hw_spi_trx (uint8_t *data, int length, spi_direction_t direction);
|
void hw_spi_rx (uint8_t *data, int length);
|
||||||
void hw_i2c_read (uint8_t i2c_address, uint8_t address, uint8_t *data, uint8_t length, void (*callback)(void));
|
void hw_spi_tx (uint8_t *data, int length);
|
||||||
void hw_i2c_write (uint8_t i2c_address, uint8_t address, uint8_t *data, uint8_t length, void (*callback)(void));
|
|
||||||
uint32_t hw_i2c_get_error (void);
|
i2c_err_t hw_i2c_trx (uint8_t i2c_address, uint8_t *tx_data, uint8_t tx_length, uint8_t *rx_data, uint8_t rx_length);
|
||||||
void hw_i2c_raw (uint8_t i2c_address, uint8_t *tx_data, uint8_t tx_length, uint8_t *rx_data, uint8_t rx_length);
|
|
||||||
void hw_i2c_disable_irq (void);
|
|
||||||
void hw_i2c_enable_irq (void);
|
|
||||||
void hw_tim_setup (tim_id_t id, uint16_t delay, void (*callback)(void));
|
|
||||||
void hw_tim_stop (tim_id_t id);
|
|
||||||
void hw_tim_disable_irq (tim_id_t id);
|
|
||||||
void hw_tim_enable_irq (tim_id_t id);
|
|
||||||
void hw_delay_ms (uint32_t ms);
|
|
||||||
void hw_crc32_reset (void);
|
void hw_crc32_reset (void);
|
||||||
uint32_t hw_crc32_calculate (uint8_t *data, uint32_t length);
|
uint32_t hw_crc32_calculate (uint8_t *data, uint32_t length);
|
||||||
|
|
||||||
uint32_t hw_flash_size (void);
|
uint32_t hw_flash_size (void);
|
||||||
|
hw_flash_t hw_flash_read (uint32_t offset);
|
||||||
void hw_flash_erase (void);
|
void hw_flash_erase (void);
|
||||||
void hw_flash_program (uint32_t offset, hw_flash_t value);
|
void hw_flash_program (uint32_t offset, hw_flash_t value);
|
||||||
hw_flash_t hw_flash_read (uint32_t offset);
|
|
||||||
void hw_reset (loader_parameters_t *parameters);
|
void hw_reset (loader_parameters_t *parameters);
|
||||||
|
|
||||||
void hw_loader_get_parameters (loader_parameters_t *parameters);
|
void hw_loader_get_parameters (loader_parameters_t *parameters);
|
||||||
void hw_set_vector_table (uint32_t offset);
|
|
||||||
void hw_init (void);
|
void hw_adc_read_voltage_temperature (uint16_t *voltage, int16_t *temperature);
|
||||||
void hw_loader_init (void);
|
|
||||||
void hw_primer_init (void);
|
void hw_primer_init (void);
|
||||||
|
void hw_loader_init (void);
|
||||||
|
void hw_app_init (void);
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -57,11 +57,13 @@ uint32_t isv_get_address (void) {
|
|||||||
return p.address;
|
return p.address;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void isv_init (void) {
|
void isv_init (void) {
|
||||||
p.address = 0;
|
p.address = 0;
|
||||||
p.ready = true;
|
p.ready = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void isv_process (void) {
|
void isv_process (void) {
|
||||||
if ((p.address != 0) && p.ready) {
|
if ((p.address != 0) && p.ready) {
|
||||||
if (isv_get_value(ISV_SETUP_TOKEN_ADDRESS) == ISV_TOKEN) {
|
if (isv_get_value(ISV_SETUP_TOKEN_ADDRESS) == ISV_TOKEN) {
|
||||||
|
@ -8,7 +8,9 @@
|
|||||||
|
|
||||||
bool isv_set_address (uint32_t address);
|
bool isv_set_address (uint32_t address);
|
||||||
uint32_t isv_get_address (void);
|
uint32_t isv_get_address (void);
|
||||||
|
|
||||||
void isv_init (void);
|
void isv_init (void);
|
||||||
|
|
||||||
void isv_process (void);
|
void isv_process (void);
|
||||||
|
|
||||||
|
|
||||||
|
@ -114,27 +114,33 @@ static void lcmxo2_write_data (uint8_t *buffer, uint32_t length) {
|
|||||||
static void lcmxo2_reset_bus (void) {
|
static void lcmxo2_reset_bus (void) {
|
||||||
#ifdef LCMXO2_I2C
|
#ifdef LCMXO2_I2C
|
||||||
uint8_t reset_data = 0;
|
uint8_t reset_data = 0;
|
||||||
hw_i2c_raw(LCMXO2_I2C_ADDR_RESET, &reset_data, sizeof(reset_data), NULL, 0);
|
hw_i2c_trx(LCMXO2_I2C_ADDR_RESET, &reset_data, sizeof(reset_data), NULL, 0);
|
||||||
#else
|
#else
|
||||||
lcmxo2_reg_set(LCMXO2_CFGCR, CFGCR_RSTE);
|
lcmxo2_reg_set(LCMXO2_CFGCR, CFGCR_RSTE);
|
||||||
lcmxo2_reg_set(LCMXO2_CFGCR, 0);
|
lcmxo2_reg_set(LCMXO2_CFGCR, 0);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static void lcmxo2_execute_cmd (uint8_t cmd, uint32_t arg, cmd_type_t type, uint8_t *buffer, uint8_t length, bool write) {
|
static bool lcmxo2_execute_cmd (uint8_t cmd, uint32_t arg, cmd_type_t type, uint8_t *buffer, uint8_t length, bool write) {
|
||||||
#ifdef LCMXO2_I2C
|
#ifdef LCMXO2_I2C
|
||||||
uint8_t packet[20] = { cmd, ((arg >> 16) & 0xFF), ((arg >> 8) & 0xFF), (arg & 0xFF) };
|
uint8_t packet[20] = { cmd, ((arg >> 16) & 0xFF), ((arg >> 8) & 0xFF), (arg & 0xFF) };
|
||||||
int packet_length = ((type == CMD_TWO_OP) ? 3 : 4);
|
int packet_length = ((type == CMD_TWO_OP) ? 3 : 4);
|
||||||
|
|
||||||
if (write) {
|
if (write) {
|
||||||
for (int i = 0; i < length; i++) {
|
for (int i = 0; i < length; i++) {
|
||||||
packet[packet_length + i] = buffer[i];
|
packet[packet_length + i] = buffer[i];
|
||||||
}
|
}
|
||||||
packet_length += length;
|
packet_length += length;
|
||||||
}
|
}
|
||||||
hw_i2c_raw(LCMXO2_I2C_ADDR_CFG, packet, packet_length, buffer, (write ? 0 : length));
|
|
||||||
|
i2c_err_t err = hw_i2c_trx(LCMXO2_I2C_ADDR_CFG, packet, packet_length, buffer, (write ? 0 : length));
|
||||||
|
|
||||||
|
return (err != I2C_OK);
|
||||||
#else
|
#else
|
||||||
uint32_t data = (cmd << 24) | (arg & 0x00FFFFFF);
|
|
||||||
lcmxo2_reg_set(LCMXO2_CFGCR, CFGCR_WBCE);
|
lcmxo2_reg_set(LCMXO2_CFGCR, CFGCR_WBCE);
|
||||||
|
|
||||||
|
uint32_t data = (cmd << 24) | (arg & 0x00FFFFFF);
|
||||||
|
|
||||||
fpga_reg_set(REG_VENDOR_DATA, data);
|
fpga_reg_set(REG_VENDOR_DATA, data);
|
||||||
fpga_reg_set(REG_VENDOR_SCR,
|
fpga_reg_set(REG_VENDOR_SCR,
|
||||||
(LCMXO2_CFGTXDR << VENDOR_SCR_ADDRESS_BIT) |
|
(LCMXO2_CFGTXDR << VENDOR_SCR_ADDRESS_BIT) |
|
||||||
@ -143,7 +149,9 @@ static void lcmxo2_execute_cmd (uint8_t cmd, uint32_t arg, cmd_type_t type, uint
|
|||||||
VENDOR_SCR_WRITE |
|
VENDOR_SCR_WRITE |
|
||||||
VENDOR_SCR_START
|
VENDOR_SCR_START
|
||||||
);
|
);
|
||||||
|
|
||||||
while (fpga_reg_get(REG_VENDOR_SCR) & VENDOR_SCR_BUSY);
|
while (fpga_reg_get(REG_VENDOR_SCR) & VENDOR_SCR_BUSY);
|
||||||
|
|
||||||
if (length > 0) {
|
if (length > 0) {
|
||||||
if (write) {
|
if (write) {
|
||||||
lcmxo2_write_data(buffer, length);
|
lcmxo2_write_data(buffer, length);
|
||||||
@ -151,82 +159,105 @@ static void lcmxo2_execute_cmd (uint8_t cmd, uint32_t arg, cmd_type_t type, uint
|
|||||||
lcmxo2_read_data(buffer, length);
|
lcmxo2_read_data(buffer, length);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
lcmxo2_reg_set(LCMXO2_CFGCR, 0);
|
lcmxo2_reg_set(LCMXO2_CFGCR, 0);
|
||||||
|
|
||||||
|
return false;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static void lcmxo2_read_device_id (uint8_t *id) {
|
static bool lcmxo2_read_device_id (uint8_t *id) {
|
||||||
lcmxo2_execute_cmd(IDCODE_PUB, 0, CMD_NORMAL, id, DEVICE_ID_SIZE, false);
|
return lcmxo2_execute_cmd(IDCODE_PUB, 0, CMD_NORMAL, id, DEVICE_ID_SIZE, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t lcmxo2_read_status (void) {
|
static uint32_t lcmxo2_read_status (uint32_t *status) {
|
||||||
uint32_t status = 0;
|
uint32_t tmp = 0;
|
||||||
lcmxo2_execute_cmd(LSC_READ_STATUS, 0, CMD_NORMAL, (uint8_t *) (&status), 4, false);
|
bool error = lcmxo2_execute_cmd(LSC_READ_STATUS, 0, CMD_NORMAL, (uint8_t *) (&tmp), 4, false);
|
||||||
return SWAP32(status);
|
*status = SWAP32(tmp);
|
||||||
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool lcmxo2_wait_busy (void) {
|
static bool lcmxo2_wait_busy (void) {
|
||||||
|
bool error;
|
||||||
uint32_t status;
|
uint32_t status;
|
||||||
do {
|
do {
|
||||||
status = lcmxo2_read_status();
|
error = lcmxo2_read_status(&status);
|
||||||
} while(status & LSC_STATUS_BUSY);
|
} while ((!error) && (status & LSC_STATUS_BUSY));
|
||||||
return (status & LSC_STATUS_FAIL);
|
return (error) || (status & LSC_STATUS_FAIL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool lcmxo2_enable_flash (void) {
|
static bool lcmxo2_enable_flash (void) {
|
||||||
#ifdef LCMXO2_I2C
|
#ifdef LCMXO2_I2C
|
||||||
lcmxo2_execute_cmd(ISC_ENABLE, 0x080000, CMD_TWO_OP, NULL, 0, false);
|
if (lcmxo2_execute_cmd(ISC_ENABLE, 0x080000, CMD_TWO_OP, NULL, 0, false)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
lcmxo2_execute_cmd(ISC_ENABLE_X, 0x080000, CMD_NORMAL, NULL, 0, false);
|
if (lcmxo2_execute_cmd(ISC_ENABLE_X, 0x080000, CMD_NORMAL, NULL, 0, false)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
return lcmxo2_wait_busy();
|
return lcmxo2_wait_busy();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void lcmxo2_disable_flash (void) {
|
static bool lcmxo2_disable_flash (void) {
|
||||||
lcmxo2_wait_busy();
|
if (lcmxo2_wait_busy()) {
|
||||||
lcmxo2_execute_cmd(ISC_DISABLE, 0, CMD_TWO_OP, NULL, 0, false);
|
return true;
|
||||||
lcmxo2_execute_cmd(ISC_NOOP, 0xFFFFFF, CMD_NORMAL, NULL, 0, false);
|
}
|
||||||
|
if (lcmxo2_execute_cmd(ISC_DISABLE, 0, CMD_TWO_OP, NULL, 0, false)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return lcmxo2_execute_cmd(ISC_NOOP, 0xFFFFFF, CMD_NORMAL, NULL, 0, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool lcmxo2_erase_featbits (void) {
|
static bool lcmxo2_erase_featbits (void) {
|
||||||
lcmxo2_execute_cmd(ISC_ERASE, ISC_ERASE_FEATURE, CMD_NORMAL, NULL, 0, false);
|
if (lcmxo2_execute_cmd(ISC_ERASE, ISC_ERASE_FEATURE, CMD_NORMAL, NULL, 0, false)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
return lcmxo2_wait_busy();
|
return lcmxo2_wait_busy();
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool lcmxo2_erase_flash (void) {
|
static bool lcmxo2_erase_flash (void) {
|
||||||
lcmxo2_execute_cmd(ISC_ERASE, (ISC_ERASE_UFM | ISC_ERASE_CFG), CMD_NORMAL, NULL, 0, false);
|
if (lcmxo2_execute_cmd(ISC_ERASE, (ISC_ERASE_UFM | ISC_ERASE_CFG), CMD_NORMAL, NULL, 0, false)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
return lcmxo2_wait_busy();
|
return lcmxo2_wait_busy();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void lcmxo2_reset_flash_address (void) {
|
static bool lcmxo2_reset_flash_address (void) {
|
||||||
lcmxo2_execute_cmd(LSC_INIT_ADDRESS, 0, CMD_NORMAL, NULL, 0, false);
|
return lcmxo2_execute_cmd(LSC_INIT_ADDRESS, 0, CMD_NORMAL, NULL, 0, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool lcmxo2_write_flash_page (uint8_t *buffer) {
|
static bool lcmxo2_write_flash_page (uint8_t *buffer) {
|
||||||
lcmxo2_execute_cmd(LSC_PROG_INCR_NV, 1, CMD_NORMAL, buffer, FLASH_PAGE_SIZE, true);
|
if (lcmxo2_execute_cmd(LSC_PROG_INCR_NV, 1, CMD_NORMAL, buffer, FLASH_PAGE_SIZE, true)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
return lcmxo2_wait_busy();
|
return lcmxo2_wait_busy();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void lcmxo2_read_flash_page (uint8_t *buffer) {
|
static bool lcmxo2_read_flash_page (uint8_t *buffer) {
|
||||||
lcmxo2_execute_cmd(LSC_READ_INCR_NV, 1, CMD_DELAYED, buffer, FLASH_PAGE_SIZE, false);
|
return lcmxo2_execute_cmd(LSC_READ_INCR_NV, 1, CMD_DELAYED, buffer, FLASH_PAGE_SIZE, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool lcmxo2_program_done (void) {
|
static bool lcmxo2_program_done (void) {
|
||||||
lcmxo2_execute_cmd(ISC_PROGRAM_DONE, 0, CMD_NORMAL, NULL, 0, false);
|
if (lcmxo2_execute_cmd(ISC_PROGRAM_DONE, 0, CMD_NORMAL, NULL, 0, false)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
return lcmxo2_wait_busy();
|
return lcmxo2_wait_busy();
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool lcmxo2_write_featbits (uint8_t *buffer) {
|
static bool lcmxo2_write_featbits (uint8_t *buffer) {
|
||||||
lcmxo2_execute_cmd(LSC_PROG_FEABITS, 0, CMD_NORMAL, buffer, FEATBITS_SIZE, true);
|
if (lcmxo2_execute_cmd(LSC_PROG_FEABITS, 0, CMD_NORMAL, buffer, FEATBITS_SIZE, true)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
return lcmxo2_wait_busy();
|
return lcmxo2_wait_busy();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void lcmxo2_read_featbits (uint8_t *buffer) {
|
static bool lcmxo2_read_featbits (uint8_t *buffer) {
|
||||||
lcmxo2_execute_cmd(LSC_READ_FEABITS, 0, CMD_NORMAL, buffer, FEATBITS_SIZE, false);
|
return lcmxo2_execute_cmd(LSC_READ_FEABITS, 0, CMD_NORMAL, buffer, FEATBITS_SIZE, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void lcmxo2_refresh (void) {
|
static bool lcmxo2_refresh (void) {
|
||||||
lcmxo2_execute_cmd(LSC_REFRESH, 0, CMD_TWO_OP, NULL, 0, false);
|
return lcmxo2_execute_cmd(LSC_REFRESH, 0, CMD_TWO_OP, NULL, 0, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
static vendor_error_t lcmxo2_fail (vendor_error_t error) {
|
static vendor_error_t lcmxo2_fail (vendor_error_t error) {
|
||||||
@ -346,20 +377,29 @@ static bool primer_check_rx_length (primer_cmd_e cmd, size_t rx_length) {
|
|||||||
static bool lcmxo2_init_featbits (void) {
|
static bool lcmxo2_init_featbits (void) {
|
||||||
uint8_t programmed[2] = { 0x00, 0x00 };
|
uint8_t programmed[2] = { 0x00, 0x00 };
|
||||||
uint8_t target[2] = { FEATBITS_0_SPI_OFF, FEATBITS_1_PROGRAMN_OFF };
|
uint8_t target[2] = { FEATBITS_0_SPI_OFF, FEATBITS_1_PROGRAMN_OFF };
|
||||||
lcmxo2_read_featbits(programmed);
|
|
||||||
|
if (lcmxo2_read_featbits(programmed)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
if ((programmed[0] == target[0]) && (programmed[1] == target[1])) {
|
if ((programmed[0] == target[0]) && (programmed[1] == target[1])) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lcmxo2_erase_featbits()) {
|
if (lcmxo2_erase_featbits()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (lcmxo2_write_featbits(target)) {
|
if (lcmxo2_write_featbits(target)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
lcmxo2_read_featbits(programmed);
|
if (lcmxo2_read_featbits(programmed)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
if ((programmed[0] != target[0]) || (programmed[1] != target[1])) {
|
if ((programmed[0] != target[0]) || (programmed[1] != target[1])) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -403,7 +443,7 @@ void vendor_initial_configuration (vendor_get_cmd_t get_cmd, vendor_send_respons
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case CMD_GET_DEVICE_ID:
|
case CMD_GET_DEVICE_ID:
|
||||||
lcmxo2_read_device_id(buffer);
|
error = lcmxo2_read_device_id(buffer);
|
||||||
tx_length = 4;
|
tx_length = 4;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -416,7 +456,7 @@ void vendor_initial_configuration (vendor_get_cmd_t get_cmd, vendor_send_respons
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case CMD_RESET_ADDRESS:
|
case CMD_RESET_ADDRESS:
|
||||||
lcmxo2_reset_flash_address();
|
error = lcmxo2_reset_flash_address();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CMD_WRITE_PAGE:
|
case CMD_WRITE_PAGE:
|
||||||
@ -424,7 +464,7 @@ void vendor_initial_configuration (vendor_get_cmd_t get_cmd, vendor_send_respons
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case CMD_READ_PAGE:
|
case CMD_READ_PAGE:
|
||||||
lcmxo2_read_flash_page(buffer);
|
error = lcmxo2_read_flash_page(buffer);
|
||||||
tx_length = FLASH_PAGE_SIZE;
|
tx_length = FLASH_PAGE_SIZE;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -437,7 +477,7 @@ void vendor_initial_configuration (vendor_get_cmd_t get_cmd, vendor_send_respons
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case CMD_REFRESH:
|
case CMD_REFRESH:
|
||||||
lcmxo2_refresh();
|
error = lcmxo2_refresh();
|
||||||
hw_delay_ms(200);
|
hw_delay_ms(200);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -2,102 +2,46 @@
|
|||||||
#include "hw.h"
|
#include "hw.h"
|
||||||
#include "led.h"
|
#include "led.h"
|
||||||
#include "rtc.h"
|
#include "rtc.h"
|
||||||
#include "task.h"
|
|
||||||
#include "timer.h"
|
#include "timer.h"
|
||||||
|
|
||||||
|
|
||||||
#define LED_MS_PER_TICK (10)
|
#define LED_REFRESH_PERIOD_MS (50)
|
||||||
#define LED_ERROR_TICKS_PERIOD (50)
|
|
||||||
#define LED_ERROR_TICKS_ON (25)
|
#define LED_PULSE_LENGTH_MS (200)
|
||||||
#define LED_ACT_TICKS_PERIOD (15)
|
|
||||||
#define LED_ACT_TICKS_ON (6)
|
#define ERROR_BLINK_PERIOD_MS (100)
|
||||||
|
#define ERROR_TOTAL_PERIOD_MS (1000)
|
||||||
|
|
||||||
|
#define CIC_ERROR_BLINKS (1)
|
||||||
|
#define RTC_ERROR_BLINKS (2)
|
||||||
|
|
||||||
|
|
||||||
static bool error_mode = false;
|
static bool activity_pulse = false;
|
||||||
static uint32_t error_timer = 0;
|
static int activity_pulse_timer = 0;
|
||||||
static volatile bool cic_error = false;
|
|
||||||
static volatile bool rtc_error = false;
|
|
||||||
|
|
||||||
static uint32_t act_timer = 0;
|
static bool cic_error = false;
|
||||||
static uint32_t current_act_counter = 0;
|
static bool rtc_error = false;
|
||||||
static volatile uint32_t next_act_counter = 0;
|
static bool error_active = false;
|
||||||
|
static int error_timer = 0;
|
||||||
|
|
||||||
|
|
||||||
static void led_task_resume (void) {
|
void led_activity_on (void) {
|
||||||
task_set_ready(TASK_ID_LED);
|
rtc_settings_t *settings = rtc_get_settings();
|
||||||
|
if (!activity_pulse && !error_active && settings->led_enabled) {
|
||||||
|
hw_gpio_set(GPIO_ID_LED);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void led_set_state (bool state, bool force) {
|
void led_activity_off (void) {
|
||||||
rtc_settings_t *settings = rtc_get_settings();
|
rtc_settings_t *settings = rtc_get_settings();
|
||||||
if (settings->led_enabled || force) {
|
if (!activity_pulse && !error_active && settings->led_enabled) {
|
||||||
if (state) {
|
|
||||||
hw_gpio_set(GPIO_ID_LED);
|
|
||||||
} else {
|
|
||||||
hw_gpio_reset(GPIO_ID_LED);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
hw_gpio_reset(GPIO_ID_LED);
|
hw_gpio_reset(GPIO_ID_LED);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void led_update_error_mode (void) {
|
void led_activity_pulse (void) {
|
||||||
if (error_mode) {
|
activity_pulse = true;
|
||||||
if (!(cic_error || rtc_error)) {
|
activity_pulse_timer = LED_PULSE_LENGTH_MS;
|
||||||
led_set_state(false, true);
|
|
||||||
error_mode = false;
|
|
||||||
act_timer = 0;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (cic_error || rtc_error) {
|
|
||||||
led_set_state(false, true);
|
|
||||||
error_mode = true;
|
|
||||||
error_timer = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void led_process_errors (void) {
|
|
||||||
if (error_timer == 0) {
|
|
||||||
error_timer = LED_ERROR_TICKS_PERIOD;
|
|
||||||
if (cic_error) {
|
|
||||||
error_timer *= 1;
|
|
||||||
} else if (rtc_error) {
|
|
||||||
error_timer *= 2;
|
|
||||||
}
|
|
||||||
error_timer += LED_ERROR_TICKS_PERIOD;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (error_timer > 0) {
|
|
||||||
error_timer -= 1;
|
|
||||||
if (error_timer >= LED_ERROR_TICKS_PERIOD) {
|
|
||||||
uint32_t error_cycle = (error_timer % LED_ERROR_TICKS_PERIOD);
|
|
||||||
if (error_cycle == LED_ERROR_TICKS_ON) {
|
|
||||||
led_set_state(true, true);
|
|
||||||
}
|
|
||||||
if (error_cycle == 0) {
|
|
||||||
led_set_state(false, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void led_process_act (void) {
|
|
||||||
if (act_timer == 0) {
|
|
||||||
if (current_act_counter != next_act_counter) {
|
|
||||||
current_act_counter = next_act_counter;
|
|
||||||
act_timer = LED_ACT_TICKS_PERIOD;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (act_timer > 0) {
|
|
||||||
act_timer -= 1;
|
|
||||||
if (act_timer == LED_ACT_TICKS_ON) {
|
|
||||||
led_set_state(true, false);
|
|
||||||
}
|
|
||||||
if (act_timer == 0) {
|
|
||||||
led_set_state(false, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -106,10 +50,16 @@ void led_blink_error (led_error_t error) {
|
|||||||
case LED_ERROR_CIC:
|
case LED_ERROR_CIC:
|
||||||
cic_error = true;
|
cic_error = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case LED_ERROR_RTC:
|
case LED_ERROR_RTC:
|
||||||
rtc_error = true;
|
rtc_error = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
error_active = (
|
||||||
|
cic_error |
|
||||||
|
rtc_error
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void led_clear_error (led_error_t error) {
|
void led_clear_error (led_error_t error) {
|
||||||
@ -117,32 +67,81 @@ void led_clear_error (led_error_t error) {
|
|||||||
case LED_ERROR_CIC:
|
case LED_ERROR_CIC:
|
||||||
cic_error = false;
|
cic_error = false;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case LED_ERROR_RTC:
|
case LED_ERROR_RTC:
|
||||||
rtc_error = false;
|
rtc_error = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void led_blink_act (void) {
|
error_active = (
|
||||||
next_act_counter += 1;
|
cic_error |
|
||||||
}
|
rtc_error
|
||||||
|
);
|
||||||
|
|
||||||
void led_task (void) {
|
if (!error_active) {
|
||||||
timer_init();
|
activity_pulse = false;
|
||||||
|
activity_pulse_timer = 0;
|
||||||
while (1) {
|
error_timer = 0;
|
||||||
hw_tim_setup(TIM_ID_LED, LED_MS_PER_TICK, led_task_resume);
|
}
|
||||||
|
}
|
||||||
led_update_error_mode();
|
|
||||||
|
|
||||||
if (error_mode) {
|
void led_init (void) {
|
||||||
led_process_errors();
|
timer_countdown_start(TIMER_ID_LED, LED_REFRESH_PERIOD_MS);
|
||||||
} else {
|
}
|
||||||
led_process_act();
|
|
||||||
}
|
|
||||||
|
void led_process (void) {
|
||||||
timer_update();
|
if (!timer_countdown_elapsed(TIMER_ID_LED)) {
|
||||||
|
return;
|
||||||
task_yield();
|
}
|
||||||
|
|
||||||
|
timer_countdown_start(TIMER_ID_LED, LED_REFRESH_PERIOD_MS);
|
||||||
|
|
||||||
|
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 {
|
||||||
|
hw_gpio_reset(GPIO_ID_LED);
|
||||||
|
}
|
||||||
|
|
||||||
|
error_timer += LED_REFRESH_PERIOD_MS;
|
||||||
|
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,10 +8,16 @@ typedef enum {
|
|||||||
} led_error_t;
|
} led_error_t;
|
||||||
|
|
||||||
|
|
||||||
|
void led_activity_on (void);
|
||||||
|
void led_activity_off (void);
|
||||||
|
void led_activity_pulse (void);
|
||||||
|
|
||||||
void led_blink_error (led_error_t error);
|
void led_blink_error (led_error_t error);
|
||||||
void led_clear_error (led_error_t error);
|
void led_clear_error (led_error_t error);
|
||||||
void led_blink_act (void);
|
|
||||||
void led_task (void);
|
void led_init (void);
|
||||||
|
|
||||||
|
void led_process (void);
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -9,6 +9,7 @@ void no_valid_image (void) {
|
|||||||
hw_gpio_set(GPIO_ID_LED);
|
hw_gpio_set(GPIO_ID_LED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void loader (void) {
|
void loader (void) {
|
||||||
if (update_check()) {
|
if (update_check()) {
|
||||||
hw_loader_init();
|
hw_loader_init();
|
||||||
|
@ -19,7 +19,7 @@ static uint8_t primer_get_command (uint8_t *buffer, uint8_t *rx_length) {
|
|||||||
uint32_t received_crc32;
|
uint32_t received_crc32;
|
||||||
uint8_t token[4];
|
uint8_t token[4];
|
||||||
|
|
||||||
while (1) {
|
while (true) {
|
||||||
hw_crc32_reset();
|
hw_crc32_reset();
|
||||||
|
|
||||||
primer_get_and_calculate_crc32(token, 4, &calculated_crc32);
|
primer_get_and_calculate_crc32(token, 4, &calculated_crc32);
|
||||||
@ -69,7 +69,10 @@ static void primer_send_response (uint8_t cmd, uint8_t *buffer, uint8_t tx_lengt
|
|||||||
|
|
||||||
void primer (void) {
|
void primer (void) {
|
||||||
hw_primer_init();
|
hw_primer_init();
|
||||||
|
|
||||||
vendor_initial_configuration(primer_get_command, primer_send_response);
|
vendor_initial_configuration(primer_get_command, primer_send_response);
|
||||||
hw_uart_wait_busy();
|
|
||||||
|
hw_uart_write_wait_busy();
|
||||||
|
|
||||||
hw_reset(NULL);
|
hw_reset(NULL);
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
#include "hw.h"
|
#include "hw.h"
|
||||||
#include "led.h"
|
#include "led.h"
|
||||||
#include "rtc.h"
|
#include "rtc.h"
|
||||||
#include "task.h"
|
#include "timer.h"
|
||||||
|
|
||||||
|
|
||||||
#define RTC_I2C_ADDRESS (0xDE)
|
#define RTC_I2C_ADDRESS (0xDE)
|
||||||
@ -28,27 +28,27 @@
|
|||||||
|
|
||||||
#define RTC_SETTINGS_VERSION (1)
|
#define RTC_SETTINGS_VERSION (1)
|
||||||
|
|
||||||
|
#define RTC_TIME_REFRESH_PERIOD_MS (500)
|
||||||
|
|
||||||
|
|
||||||
static rtc_time_t rtc_time = {
|
static rtc_time_t rtc_time = {
|
||||||
.second = 0x00,
|
.second = 0x00,
|
||||||
.minute = 0x00,
|
.minute = 0x00,
|
||||||
.hour = 0x12,
|
.hour = 0x12,
|
||||||
.weekday = 0x02,
|
.weekday = 0x01,
|
||||||
.day = 0x01,
|
.day = 0x01,
|
||||||
.month = 0x03,
|
.month = 0x01,
|
||||||
.year = 0x22
|
.year = 0x24
|
||||||
};
|
};
|
||||||
static bool rtc_time_valid = false;
|
static bool rtc_time_pending = false;
|
||||||
static volatile bool rtc_time_pending = false;
|
|
||||||
|
|
||||||
static uint8_t rtc_region = 0xFF;
|
static uint8_t rtc_region = 0xFF;
|
||||||
static volatile bool rtc_region_pending = false;
|
static bool rtc_region_pending = false;
|
||||||
|
|
||||||
static rtc_settings_t rtc_settings = {
|
static rtc_settings_t rtc_settings = {
|
||||||
.led_enabled = true,
|
.led_enabled = true,
|
||||||
};
|
};
|
||||||
static volatile bool rtc_settings_pending = false;
|
static bool rtc_settings_pending = false;
|
||||||
static volatile bool rtc_initialized = false;
|
|
||||||
|
|
||||||
static const uint8_t rtc_regs_bit_mask[7] = {
|
static const uint8_t rtc_regs_bit_mask[7] = {
|
||||||
0b01111111,
|
0b01111111,
|
||||||
@ -61,30 +61,29 @@ static const uint8_t rtc_regs_bit_mask[7] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
static void rtc_task_resume (void) {
|
static bool rtc_read (uint8_t address, uint8_t *data, uint8_t length) {
|
||||||
task_set_ready(TASK_ID_RTC);
|
if (hw_i2c_trx(RTC_I2C_ADDRESS, &address, 1, data, length) != I2C_OK) {
|
||||||
}
|
led_blink_error(LED_ERROR_RTC);
|
||||||
|
return true;
|
||||||
static void rtc_on_error (void) {
|
|
||||||
rtc_time_valid = false;
|
|
||||||
led_blink_error(LED_ERROR_RTC);
|
|
||||||
task_yield();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void rtc_read (uint8_t address, uint8_t *data, uint8_t length) {
|
|
||||||
hw_i2c_read(RTC_I2C_ADDRESS, address, data, length, rtc_task_resume);
|
|
||||||
task_yield();
|
|
||||||
if (hw_i2c_get_error()) {
|
|
||||||
rtc_on_error();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rtc_write (uint8_t address, uint8_t *data, uint8_t length) {
|
static bool rtc_write (uint8_t address, uint8_t *data, uint8_t length) {
|
||||||
hw_i2c_write(RTC_I2C_ADDRESS, address, data, length, rtc_task_resume);
|
uint8_t buffer[16];
|
||||||
task_yield();
|
buffer[0] = address;
|
||||||
if (hw_i2c_get_error()) {
|
|
||||||
rtc_on_error();
|
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) {
|
static void rtc_sanitize_time (uint8_t *regs) {
|
||||||
@ -98,29 +97,25 @@ static void rtc_osc_stop (void) {
|
|||||||
|
|
||||||
rtc_write(RTC_ADDRESS_RTCSEC, &tmp, 1);
|
rtc_write(RTC_ADDRESS_RTCSEC, &tmp, 1);
|
||||||
|
|
||||||
do {
|
while ((!rtc_read(RTC_ADDRESS_RTCWKDAY, &tmp, 1)) && (tmp & RTC_RTCWKDAY_OSCRUN));
|
||||||
rtc_read(RTC_ADDRESS_RTCWKDAY, &tmp, 1);
|
|
||||||
} while (tmp & RTC_RTCWKDAY_OSCRUN);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rtc_read_time (void) {
|
static void rtc_read_time (void) {
|
||||||
uint8_t regs[7];
|
uint8_t regs[7];
|
||||||
|
|
||||||
rtc_read(RTC_ADDRESS_RTCSEC, regs, 7);
|
if (rtc_read(RTC_ADDRESS_RTCSEC, regs, 7)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
rtc_sanitize_time(regs);
|
rtc_sanitize_time(regs);
|
||||||
|
|
||||||
if (!rtc_time_pending) {
|
rtc_time.second = regs[0];
|
||||||
rtc_time.second = regs[0];
|
rtc_time.minute = regs[1];
|
||||||
rtc_time.minute = regs[1];
|
rtc_time.hour = regs[2];
|
||||||
rtc_time.hour = regs[2];
|
rtc_time.weekday = regs[3];
|
||||||
rtc_time.weekday = regs[3];
|
rtc_time.day = regs[4];
|
||||||
rtc_time.day = regs[4];
|
rtc_time.month = regs[5];
|
||||||
rtc_time.month = regs[5];
|
rtc_time.year = regs[6];
|
||||||
rtc_time.year = regs[6];
|
|
||||||
|
|
||||||
rtc_time_valid = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rtc_write_time (void) {
|
static void rtc_write_time (void) {
|
||||||
@ -161,12 +156,58 @@ static void rtc_write_settings (void) {
|
|||||||
rtc_write(RTC_ADDRESS_SRAM_SETTINGS, (uint8_t *) (&rtc_settings), sizeof(rtc_settings));
|
rtc_write(RTC_ADDRESS_SRAM_SETTINGS, (uint8_t *) (&rtc_settings), sizeof(rtc_settings));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rtc_init (void) {
|
|
||||||
|
void rtc_get_time (rtc_time_t *time) {
|
||||||
|
time->second = rtc_time.second;
|
||||||
|
time->minute = rtc_time.minute;
|
||||||
|
time->hour = rtc_time.hour;
|
||||||
|
time->weekday = rtc_time.weekday;
|
||||||
|
time->day = rtc_time.day;
|
||||||
|
time->month = rtc_time.month;
|
||||||
|
time->year = rtc_time.year;
|
||||||
|
}
|
||||||
|
|
||||||
|
void rtc_set_time (rtc_time_t *time) {
|
||||||
|
rtc_time.second = time->second;
|
||||||
|
rtc_time.minute = time->minute;
|
||||||
|
rtc_time.hour = time->hour;
|
||||||
|
rtc_time.weekday = time->weekday;
|
||||||
|
rtc_time.day = time->day;
|
||||||
|
rtc_time.month = time->month;
|
||||||
|
rtc_time.year = time->year;
|
||||||
|
rtc_time_pending = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint8_t rtc_get_region (void) {
|
||||||
|
return rtc_region;
|
||||||
|
}
|
||||||
|
|
||||||
|
void rtc_set_region (uint8_t region) {
|
||||||
|
rtc_region = region;
|
||||||
|
rtc_region_pending = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
rtc_settings_t *rtc_get_settings (void) {
|
||||||
|
return (&rtc_settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
void rtc_save_settings (void) {
|
||||||
|
rtc_settings_pending = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void rtc_init (void) {
|
||||||
bool uninitialized = false;
|
bool uninitialized = false;
|
||||||
const char *magic = "SC64";
|
const char *magic = "SC64";
|
||||||
uint8_t buffer[4];
|
uint8_t buffer[4];
|
||||||
uint32_t settings_version;
|
uint32_t settings_version;
|
||||||
|
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
buffer[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
rtc_read(RTC_ADDRESS_SRAM_MAGIC, buffer, 4);
|
rtc_read(RTC_ADDRESS_SRAM_MAGIC, buffer, 4);
|
||||||
|
|
||||||
for (int i = 0; i < 4; i++) {
|
for (int i = 0; i < 4; i++) {
|
||||||
@ -179,7 +220,6 @@ static void rtc_init (void) {
|
|||||||
if (uninitialized) {
|
if (uninitialized) {
|
||||||
buffer[0] = 0;
|
buffer[0] = 0;
|
||||||
rtc_write(RTC_ADDRESS_SRAM_MAGIC, (uint8_t *) (magic), 4);
|
rtc_write(RTC_ADDRESS_SRAM_MAGIC, (uint8_t *) (magic), 4);
|
||||||
rtc_write(RTC_ADDRESS_CONTROL, buffer, 1);
|
|
||||||
rtc_write(RTC_ADDRESS_OSCTRIM, buffer, 1);
|
rtc_write(RTC_ADDRESS_OSCTRIM, buffer, 1);
|
||||||
rtc_write_time();
|
rtc_write_time();
|
||||||
rtc_write_region();
|
rtc_write_region();
|
||||||
@ -192,143 +232,73 @@ static void rtc_init (void) {
|
|||||||
rtc_write(RTC_ADDRESS_SRAM_VERSION, (uint8_t *) (&settings_version), 4);
|
rtc_write(RTC_ADDRESS_SRAM_VERSION, (uint8_t *) (&settings_version), 4);
|
||||||
rtc_write_settings();
|
rtc_write_settings();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool rtc_is_initialized (void) {
|
|
||||||
return rtc_initialized;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool rtc_get_time (rtc_time_t *time) {
|
|
||||||
bool vaild;
|
|
||||||
|
|
||||||
hw_i2c_disable_irq();
|
|
||||||
hw_tim_disable_irq(TIM_ID_RTC);
|
|
||||||
|
|
||||||
time->second = rtc_time.second;
|
|
||||||
time->minute = rtc_time.minute;
|
|
||||||
time->hour = rtc_time.hour;
|
|
||||||
time->weekday = rtc_time.weekday;
|
|
||||||
time->day = rtc_time.day;
|
|
||||||
time->month = rtc_time.month;
|
|
||||||
time->year = rtc_time.year;
|
|
||||||
vaild = rtc_time_valid;
|
|
||||||
|
|
||||||
hw_tim_enable_irq(TIM_ID_RTC);
|
|
||||||
hw_i2c_enable_irq();
|
|
||||||
|
|
||||||
return vaild;
|
|
||||||
}
|
|
||||||
|
|
||||||
void rtc_set_time (rtc_time_t *time) {
|
|
||||||
hw_i2c_disable_irq();
|
|
||||||
hw_tim_disable_irq(TIM_ID_RTC);
|
|
||||||
|
|
||||||
rtc_time.second = time->second;
|
|
||||||
rtc_time.minute = time->minute;
|
|
||||||
rtc_time.hour = time->hour;
|
|
||||||
rtc_time.weekday = time->weekday;
|
|
||||||
rtc_time.day = time->day;
|
|
||||||
rtc_time.month = time->month;
|
|
||||||
rtc_time.year = time->year;
|
|
||||||
rtc_time_pending = true;
|
|
||||||
|
|
||||||
hw_tim_enable_irq(TIM_ID_RTC);
|
|
||||||
hw_i2c_enable_irq();
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t rtc_get_region (void) {
|
|
||||||
return rtc_region;
|
|
||||||
}
|
|
||||||
|
|
||||||
void rtc_set_region (uint8_t region) {
|
|
||||||
rtc_region = region;
|
|
||||||
rtc_region_pending = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
rtc_settings_t *rtc_get_settings (void) {
|
|
||||||
return (&rtc_settings);
|
|
||||||
}
|
|
||||||
|
|
||||||
void rtc_set_settings (rtc_settings_t *settings) {
|
|
||||||
hw_tim_disable_irq(TIM_ID_LED);
|
|
||||||
|
|
||||||
rtc_settings = *settings;
|
|
||||||
rtc_settings_pending = true;
|
|
||||||
|
|
||||||
hw_tim_enable_irq(TIM_ID_LED);
|
|
||||||
}
|
|
||||||
|
|
||||||
void rtc_task (void) {
|
|
||||||
rtc_init();
|
|
||||||
|
|
||||||
|
rtc_read_time();
|
||||||
rtc_read_region();
|
rtc_read_region();
|
||||||
rtc_read_settings();
|
rtc_read_settings();
|
||||||
|
|
||||||
rtc_initialized = true;
|
timer_countdown_start(TIMER_ID_RTC, RTC_TIME_REFRESH_PERIOD_MS);
|
||||||
|
|
||||||
while (1) {
|
|
||||||
if (rtc_time_pending) {
|
|
||||||
rtc_time_pending = false;
|
|
||||||
rtc_write_time();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rtc_region_pending) {
|
|
||||||
rtc_region_pending = false;
|
|
||||||
rtc_write_region();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rtc_settings_pending) {
|
|
||||||
rtc_settings_pending = false;
|
|
||||||
rtc_write_settings();
|
|
||||||
}
|
|
||||||
|
|
||||||
rtc_read_time();
|
|
||||||
|
|
||||||
hw_tim_setup(TIM_ID_RTC, 50, rtc_task_resume);
|
|
||||||
|
|
||||||
task_yield();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void rtc_process (void) {
|
void rtc_process (void) {
|
||||||
rtc_time_t time;
|
|
||||||
uint32_t data[2];
|
|
||||||
uint32_t scr = fpga_reg_get(REG_RTC_SCR);
|
uint32_t scr = fpga_reg_get(REG_RTC_SCR);
|
||||||
|
|
||||||
if ((scr & RTC_SCR_PENDING) && ((scr & RTC_SCR_MAGIC_MASK) == RTC_SCR_MAGIC)) {
|
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[0] = fpga_reg_get(REG_RTC_TIME_0);
|
||||||
data[1] = fpga_reg_get(REG_RTC_TIME_1);
|
data[1] = fpga_reg_get(REG_RTC_TIME_1);
|
||||||
|
|
||||||
time.weekday = ((data[0] >> 24) & 0xFF) + 1;
|
rtc_time.weekday = ((data[0] >> 24) & 0xFF) + 1;
|
||||||
time.hour = ((data[0] >> 16) & 0xFF);
|
rtc_time.hour = ((data[0] >> 16) & 0xFF);
|
||||||
time.minute = ((data[0] >> 8) & 0xFF);
|
rtc_time.minute = ((data[0] >> 8) & 0xFF);
|
||||||
time.second = ((data[0] >> 0) & 0xFF);
|
rtc_time.second = ((data[0] >> 0) & 0xFF);
|
||||||
time.year = ((data[1] >> 16) & 0xFF);
|
rtc_time.year = ((data[1] >> 16) & 0xFF);
|
||||||
time.month = ((data[1] >> 8) & 0xFF);
|
rtc_time.month = ((data[1] >> 8) & 0xFF);
|
||||||
time.day = ((data[1] >> 0) & 0xFF);
|
rtc_time.day = ((data[1] >> 0) & 0xFF);
|
||||||
|
rtc_time_pending = true;
|
||||||
rtc_set_time(&time);
|
|
||||||
|
|
||||||
fpga_reg_set(REG_RTC_TIME_0, data[0]);
|
fpga_reg_set(REG_RTC_TIME_0, data[0]);
|
||||||
fpga_reg_set(REG_RTC_TIME_1, data[1]);
|
fpga_reg_set(REG_RTC_TIME_1, data[1]);
|
||||||
fpga_reg_set(REG_RTC_SCR, RTC_SCR_DONE);
|
fpga_reg_set(REG_RTC_SCR, RTC_SCR_DONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
rtc_get_time(&time);
|
if (rtc_time_pending) {
|
||||||
|
rtc_time_pending = false;
|
||||||
|
rtc_write_time();
|
||||||
|
}
|
||||||
|
|
||||||
data[0] = (
|
if (rtc_region_pending) {
|
||||||
((time.weekday - 1) << 24) |
|
rtc_region_pending = false;
|
||||||
(time.hour << 16) |
|
rtc_write_region();
|
||||||
(time.minute << 8) |
|
}
|
||||||
(time.second << 0)
|
|
||||||
);
|
|
||||||
data[1] = (
|
|
||||||
(time.year << 16) |
|
|
||||||
(time.month << 8) |
|
|
||||||
(time.day << 0)
|
|
||||||
);
|
|
||||||
|
|
||||||
fpga_reg_set(REG_RTC_TIME_0, data[0]);
|
if (rtc_settings_pending) {
|
||||||
fpga_reg_set(REG_RTC_TIME_1, data[1]);
|
rtc_settings_pending = false;
|
||||||
|
rtc_write_settings();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (timer_countdown_elapsed(TIMER_ID_RTC)) {
|
||||||
|
timer_countdown_start(TIMER_ID_RTC, RTC_TIME_REFRESH_PERIOD_MS);
|
||||||
|
|
||||||
|
rtc_read_time();
|
||||||
|
|
||||||
|
uint32_t data[2];
|
||||||
|
|
||||||
|
data[0] = (
|
||||||
|
((rtc_time.weekday - 1) << 24) |
|
||||||
|
(rtc_time.hour << 16) |
|
||||||
|
(rtc_time.minute << 8) |
|
||||||
|
(rtc_time.second << 0)
|
||||||
|
);
|
||||||
|
data[1] = (
|
||||||
|
(rtc_time.year << 16) |
|
||||||
|
(rtc_time.month << 8) |
|
||||||
|
(rtc_time.day << 0)
|
||||||
|
);
|
||||||
|
|
||||||
|
fpga_reg_set(REG_RTC_TIME_0, data[0]);
|
||||||
|
fpga_reg_set(REG_RTC_TIME_1, data[1]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,28 +7,31 @@
|
|||||||
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
volatile uint8_t second;
|
uint8_t second;
|
||||||
volatile uint8_t minute;
|
uint8_t minute;
|
||||||
volatile uint8_t hour;
|
uint8_t hour;
|
||||||
volatile uint8_t weekday;
|
uint8_t weekday;
|
||||||
volatile uint8_t day;
|
uint8_t day;
|
||||||
volatile uint8_t month;
|
uint8_t month;
|
||||||
volatile uint8_t year;
|
uint8_t year;
|
||||||
} rtc_time_t;
|
} rtc_time_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
volatile bool led_enabled;
|
bool led_enabled;
|
||||||
} rtc_settings_t;
|
} rtc_settings_t;
|
||||||
|
|
||||||
|
|
||||||
bool rtc_is_initialized (void);
|
void rtc_get_time (rtc_time_t *time);
|
||||||
bool rtc_get_time (rtc_time_t *time);
|
|
||||||
void rtc_set_time (rtc_time_t *time);
|
void rtc_set_time (rtc_time_t *time);
|
||||||
|
|
||||||
uint8_t rtc_get_region (void);
|
uint8_t rtc_get_region (void);
|
||||||
void rtc_set_region (uint8_t region);
|
void rtc_set_region (uint8_t region);
|
||||||
|
|
||||||
rtc_settings_t *rtc_get_settings (void);
|
rtc_settings_t *rtc_get_settings (void);
|
||||||
void rtc_set_settings (rtc_settings_t *settings);
|
void rtc_save_settings (void);
|
||||||
void rtc_task (void);
|
|
||||||
|
void rtc_init (void);
|
||||||
|
|
||||||
void rtc_process (void);
|
void rtc_process (void);
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,9 +1,7 @@
|
|||||||
#include <stdbool.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include "fpga.h"
|
#include "fpga.h"
|
||||||
#include "hw.h"
|
#include "hw.h"
|
||||||
#include "led.h"
|
|
||||||
#include "sd.h"
|
#include "sd.h"
|
||||||
|
#include "timer.h"
|
||||||
|
|
||||||
|
|
||||||
#define SD_INIT_BUFFER_ADDRESS (0x05002800UL)
|
#define SD_INIT_BUFFER_ADDRESS (0x05002800UL)
|
||||||
@ -33,6 +31,8 @@
|
|||||||
#define SWITCH_FUNCTION_GROUP_1 (SD_INIT_BUFFER_ADDRESS + 12)
|
#define SWITCH_FUNCTION_GROUP_1 (SD_INIT_BUFFER_ADDRESS + 12)
|
||||||
#define SWITCH_FUNCTION_GROUP_1_HS (1 << 1)
|
#define SWITCH_FUNCTION_GROUP_1_HS (1 << 1)
|
||||||
|
|
||||||
|
#define TIMEOUT_INIT_MS (1000)
|
||||||
|
|
||||||
#define DAT_BLOCK_MAX_COUNT (256)
|
#define DAT_BLOCK_MAX_COUNT (256)
|
||||||
#define DAT_TIMEOUT_INIT_MS (2000)
|
#define DAT_TIMEOUT_INIT_MS (2000)
|
||||||
#define DAT_TIMEOUT_DATA_MS (5000)
|
#define DAT_TIMEOUT_DATA_MS (5000)
|
||||||
@ -60,6 +60,12 @@ typedef enum {
|
|||||||
DAT_WRITE,
|
DAT_WRITE,
|
||||||
} dat_mode_t;
|
} dat_mode_t;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
DAT_OK,
|
||||||
|
DAT_ERR_IO,
|
||||||
|
DAT_ERR_TIMEOUT,
|
||||||
|
} dat_err_t;
|
||||||
|
|
||||||
|
|
||||||
struct process {
|
struct process {
|
||||||
bool card_initialized;
|
bool card_initialized;
|
||||||
@ -67,7 +73,6 @@ struct process {
|
|||||||
uint32_t rca;
|
uint32_t rca;
|
||||||
uint8_t csd[16];
|
uint8_t csd[16];
|
||||||
uint8_t cid[16];
|
uint8_t cid[16];
|
||||||
volatile bool timeout;
|
|
||||||
bool byte_swap;
|
bool byte_swap;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -75,24 +80,6 @@ struct process {
|
|||||||
static struct process p;
|
static struct process p;
|
||||||
|
|
||||||
|
|
||||||
static void sd_trigger_timeout (void) {
|
|
||||||
p.timeout = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void sd_prepare_timeout (uint16_t value) {
|
|
||||||
p.timeout = false;
|
|
||||||
hw_tim_setup(TIM_ID_SD, value, sd_trigger_timeout);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool sd_did_timeout (void) {
|
|
||||||
return p.timeout;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void sd_clear_timeout (void) {
|
|
||||||
hw_tim_stop(TIM_ID_SD);
|
|
||||||
p.timeout = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void sd_set_clock (sd_clock_t mode) {
|
static void sd_set_clock (sd_clock_t mode) {
|
||||||
fpga_reg_set(REG_SD_SCR, SD_SCR_CLOCK_MODE_OFF);
|
fpga_reg_set(REG_SD_SCR, SD_SCR_CLOCK_MODE_OFF);
|
||||||
|
|
||||||
@ -198,22 +185,24 @@ static void sd_dat_abort (void) {
|
|||||||
fpga_reg_set(REG_SD_DAT, SD_DAT_STOP | SD_DAT_FIFO_FLUSH);
|
fpga_reg_set(REG_SD_DAT, SD_DAT_STOP | SD_DAT_FIFO_FLUSH);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool sd_dat_wait (uint16_t timeout) {
|
static dat_err_t sd_dat_wait (uint16_t timeout_ms) {
|
||||||
sd_prepare_timeout(timeout);
|
timer_countdown_start(TIMER_ID_SD, timeout_ms);
|
||||||
|
|
||||||
do {
|
do {
|
||||||
uint32_t sd_dat = fpga_reg_get(REG_SD_DAT);
|
uint32_t sd_dat = fpga_reg_get(REG_SD_DAT);
|
||||||
uint32_t sd_dma_scr = fpga_reg_get(REG_SD_DMA_SCR);
|
uint32_t sd_dma_scr = fpga_reg_get(REG_SD_DMA_SCR);
|
||||||
led_blink_act();
|
|
||||||
if ((!(sd_dat & SD_DAT_BUSY)) && (!(sd_dma_scr & DMA_SCR_BUSY))) {
|
if ((!(sd_dat & SD_DAT_BUSY)) && (!(sd_dma_scr & DMA_SCR_BUSY))) {
|
||||||
sd_clear_timeout();
|
if (sd_dat & SD_DAT_ERROR) {
|
||||||
return (sd_dat & SD_DAT_ERROR);
|
sd_dat_abort();
|
||||||
|
return DAT_ERR_IO;
|
||||||
|
}
|
||||||
|
return DAT_OK;
|
||||||
}
|
}
|
||||||
} while (!sd_did_timeout());
|
} while (!timer_countdown_elapsed(TIMER_ID_SD));
|
||||||
|
|
||||||
sd_dat_abort();
|
sd_dat_abort();
|
||||||
|
|
||||||
return true;
|
return DAT_ERR_TIMEOUT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -231,8 +220,6 @@ bool sd_card_init (void) {
|
|||||||
p.card_initialized = true;
|
p.card_initialized = true;
|
||||||
p.rca = 0;
|
p.rca = 0;
|
||||||
|
|
||||||
led_blink_act();
|
|
||||||
|
|
||||||
sd_set_clock(CLOCK_400KHZ);
|
sd_set_clock(CLOCK_400KHZ);
|
||||||
|
|
||||||
sd_cmd(0, 0, RSP_NONE, NULL);
|
sd_cmd(0, 0, RSP_NONE, NULL);
|
||||||
@ -248,11 +235,11 @@ bool sd_card_init (void) {
|
|||||||
arg = (ACMD41_ARG_HCS | ACMD41_ARG_OCR);
|
arg = (ACMD41_ARG_HCS | ACMD41_ARG_OCR);
|
||||||
}
|
}
|
||||||
|
|
||||||
sd_prepare_timeout(1000);
|
timer_countdown_start(TIMER_ID_SD, TIMEOUT_INIT_MS);
|
||||||
do {
|
do {
|
||||||
if (sd_did_timeout()) {
|
if (timer_countdown_elapsed(TIMER_ID_SD)) {
|
||||||
sd_card_deinit();
|
sd_card_deinit();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (sd_acmd(41, arg, RSP_R3, &rsp)) {
|
if (sd_acmd(41, arg, RSP_R3, &rsp)) {
|
||||||
sd_card_deinit();
|
sd_card_deinit();
|
||||||
@ -266,8 +253,7 @@ bool sd_card_init (void) {
|
|||||||
p.card_type_block = (rsp & R3_CCS);
|
p.card_type_block = (rsp & R3_CCS);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} while (1);
|
} while (true);
|
||||||
sd_clear_timeout();
|
|
||||||
|
|
||||||
if (sd_cmd(2, 0, RSP_R2, NULL)) {
|
if (sd_cmd(2, 0, RSP_R2, NULL)) {
|
||||||
sd_card_deinit();
|
sd_card_deinit();
|
||||||
@ -308,8 +294,7 @@ bool sd_card_init (void) {
|
|||||||
sd_card_deinit();
|
sd_card_deinit();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
sd_dat_wait(DAT_TIMEOUT_INIT_MS);
|
if (sd_dat_wait(DAT_TIMEOUT_INIT_MS) == DAT_ERR_TIMEOUT) {
|
||||||
if (sd_did_timeout()) {
|
|
||||||
sd_card_deinit();
|
sd_card_deinit();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -326,8 +311,7 @@ bool sd_card_init (void) {
|
|||||||
sd_card_deinit();
|
sd_card_deinit();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
sd_dat_wait(DAT_TIMEOUT_INIT_MS);
|
if (sd_dat_wait(DAT_TIMEOUT_INIT_MS) == DAT_ERR_TIMEOUT) {
|
||||||
if (sd_did_timeout()) {
|
|
||||||
sd_card_deinit();
|
sd_card_deinit();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -389,6 +373,7 @@ bool sd_set_byte_swap (bool enabled) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool sd_write_sectors (uint32_t address, uint32_t sector, uint32_t count) {
|
bool sd_write_sectors (uint32_t address, uint32_t sector, uint32_t count) {
|
||||||
if (!p.card_initialized || (count == 0)) {
|
if (!p.card_initialized || (count == 0)) {
|
||||||
return true;
|
return true;
|
||||||
@ -400,13 +385,11 @@ bool sd_write_sectors (uint32_t address, uint32_t sector, uint32_t count) {
|
|||||||
|
|
||||||
while (count > 0) {
|
while (count > 0) {
|
||||||
uint32_t blocks = ((count > DAT_BLOCK_MAX_COUNT) ? DAT_BLOCK_MAX_COUNT : count);
|
uint32_t blocks = ((count > DAT_BLOCK_MAX_COUNT) ? DAT_BLOCK_MAX_COUNT : count);
|
||||||
led_blink_act();
|
|
||||||
if (sd_cmd(25, sector, RSP_R1, NULL)) {
|
if (sd_cmd(25, sector, RSP_R1, NULL)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
sd_dat_prepare(address, blocks, DAT_WRITE);
|
sd_dat_prepare(address, blocks, DAT_WRITE);
|
||||||
if (sd_dat_wait(DAT_TIMEOUT_DATA_MS)) {
|
if (sd_dat_wait(DAT_TIMEOUT_DATA_MS) != DAT_OK) {
|
||||||
sd_dat_abort();
|
|
||||||
sd_cmd(12, 0, RSP_R1b, NULL);
|
sd_cmd(12, 0, RSP_R1b, NULL);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -434,16 +417,13 @@ bool sd_read_sectors (uint32_t address, uint32_t sector, uint32_t count) {
|
|||||||
|
|
||||||
while (count > 0) {
|
while (count > 0) {
|
||||||
uint32_t blocks = ((count > DAT_BLOCK_MAX_COUNT) ? DAT_BLOCK_MAX_COUNT : count);
|
uint32_t blocks = ((count > DAT_BLOCK_MAX_COUNT) ? DAT_BLOCK_MAX_COUNT : count);
|
||||||
led_blink_act();
|
|
||||||
sd_dat_prepare(address, blocks, DAT_READ);
|
sd_dat_prepare(address, blocks, DAT_READ);
|
||||||
if (sd_cmd(18, sector, RSP_R1, NULL)) {
|
if (sd_cmd(18, sector, RSP_R1, NULL)) {
|
||||||
sd_dat_abort();
|
sd_dat_abort();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (sd_dat_wait(DAT_TIMEOUT_DATA_MS)) {
|
if (sd_dat_wait(DAT_TIMEOUT_DATA_MS) != DAT_OK) {
|
||||||
if (sd_did_timeout()) {
|
sd_cmd(12, 0, RSP_R1b, NULL);
|
||||||
sd_cmd(12, 0, RSP_R1b, NULL);
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
sd_cmd(12, 0, RSP_R1b, NULL);
|
sd_cmd(12, 0, RSP_R1b, NULL);
|
||||||
@ -455,6 +435,7 @@ bool sd_read_sectors (uint32_t address, uint32_t sector, uint32_t count) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool sd_optimize_sectors (uint32_t address, uint32_t *sector_table, uint32_t count, sd_process_sectors_t sd_process_sectors) {
|
bool sd_optimize_sectors (uint32_t address, uint32_t *sector_table, uint32_t count, sd_process_sectors_t sd_process_sectors) {
|
||||||
uint32_t starting_sector = 0;
|
uint32_t starting_sector = 0;
|
||||||
uint32_t sectors_to_process = 0;
|
uint32_t sectors_to_process = 0;
|
||||||
@ -483,12 +464,14 @@ bool sd_optimize_sectors (uint32_t address, uint32_t *sector_table, uint32_t cou
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void sd_init (void) {
|
void sd_init (void) {
|
||||||
p.card_initialized = false;
|
p.card_initialized = false;
|
||||||
p.byte_swap = false;
|
p.byte_swap = false;
|
||||||
sd_set_clock(CLOCK_STOP);
|
sd_set_clock(CLOCK_STOP);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void sd_process (void) {
|
void sd_process (void) {
|
||||||
if (p.card_initialized && !sd_card_is_inserted()) {
|
if (p.card_initialized && !sd_card_is_inserted()) {
|
||||||
sd_card_deinit();
|
sd_card_deinit();
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
|
||||||
#define SD_SECTOR_SIZE (512)
|
#define SD_SECTOR_SIZE (512)
|
||||||
@ -18,10 +19,14 @@ bool sd_card_is_inserted (void);
|
|||||||
uint32_t sd_card_get_status (void);
|
uint32_t sd_card_get_status (void);
|
||||||
bool sd_card_get_info (uint32_t address);
|
bool sd_card_get_info (uint32_t address);
|
||||||
bool sd_set_byte_swap (bool enabled);
|
bool sd_set_byte_swap (bool enabled);
|
||||||
|
|
||||||
bool sd_write_sectors (uint32_t address, uint32_t sector, uint32_t count);
|
bool sd_write_sectors (uint32_t address, uint32_t sector, uint32_t count);
|
||||||
bool sd_read_sectors (uint32_t address, uint32_t sector, uint32_t count);
|
bool sd_read_sectors (uint32_t address, uint32_t sector, uint32_t count);
|
||||||
|
|
||||||
bool sd_optimize_sectors (uint32_t address, uint32_t *sector_table, uint32_t count, sd_process_sectors_t sd_process_sectors);
|
bool sd_optimize_sectors (uint32_t address, uint32_t *sector_table, uint32_t count, sd_process_sectors_t sd_process_sectors);
|
||||||
|
|
||||||
void sd_init (void);
|
void sd_init (void);
|
||||||
|
|
||||||
void sd_process (void);
|
void sd_process (void);
|
||||||
|
|
||||||
|
|
||||||
|
@ -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)
|
|
||||||
);
|
|
||||||
}
|
|
@ -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
|
|
@ -2,29 +2,55 @@
|
|||||||
#include "timer.h"
|
#include "timer.h"
|
||||||
|
|
||||||
|
|
||||||
static volatile uint32_t timer[__TIMER_ID_COUNT];
|
#define TIMER_PERIOD_MS (25)
|
||||||
|
|
||||||
|
|
||||||
uint32_t timer_get (timer_id_t id) {
|
typedef struct {
|
||||||
return (uint32_t) (timer[id]);
|
volatile bool pending;
|
||||||
}
|
volatile bool running;
|
||||||
|
volatile uint32_t value;
|
||||||
|
} timer_t;
|
||||||
|
|
||||||
void timer_set (timer_id_t id, uint32_t ticks) {
|
static timer_t timer[__TIMER_ID_COUNT];
|
||||||
hw_tim_disable_irq(TIM_ID_LED);
|
|
||||||
timer[id] = ticks;
|
|
||||||
hw_tim_enable_irq(TIM_ID_LED);
|
|
||||||
}
|
|
||||||
|
|
||||||
void timer_init (void) {
|
|
||||||
|
static void timer_update (void) {
|
||||||
for (timer_id_t id = 0; id < __TIMER_ID_COUNT; id++) {
|
for (timer_id_t id = 0; id < __TIMER_ID_COUNT; id++) {
|
||||||
timer[id] = 0;
|
if (timer[id].value > 0) {
|
||||||
}
|
timer[id].value -= 1;
|
||||||
}
|
}
|
||||||
|
if (timer[id].pending) {
|
||||||
void timer_update (void) {
|
timer[id].pending = false;
|
||||||
for (timer_id_t id = 0; id < __TIMER_ID_COUNT; id++) {
|
} else if (timer[id].value == 0) {
|
||||||
if (timer[id] > 0) {
|
timer[id].running = false;
|
||||||
timer[id] -= 1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void timer_countdown_start (timer_id_t id, uint32_t value_ms) {
|
||||||
|
hw_enter_critical();
|
||||||
|
if (value_ms > 0) {
|
||||||
|
timer[id].pending = true;
|
||||||
|
timer[id].running = true;
|
||||||
|
timer[id].value = ((value_ms + (TIMER_PERIOD_MS - 1)) / TIMER_PERIOD_MS);
|
||||||
|
}
|
||||||
|
hw_exit_critical();
|
||||||
|
}
|
||||||
|
|
||||||
|
void timer_countdown_abort (timer_id_t id) {
|
||||||
|
hw_enter_critical();
|
||||||
|
timer[id].pending = false;
|
||||||
|
timer[id].running = false;
|
||||||
|
timer[id].value = 0;
|
||||||
|
hw_exit_critical();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool timer_countdown_elapsed (timer_id_t id) {
|
||||||
|
return (!timer[id].running);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void timer_init (void) {
|
||||||
|
hw_systick_config(TIMER_PERIOD_MS, timer_update);
|
||||||
|
}
|
||||||
|
@ -2,20 +2,26 @@
|
|||||||
#define TIMER_H__
|
#define TIMER_H__
|
||||||
|
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
TIMER_ID_DD,
|
||||||
|
TIMER_ID_LED,
|
||||||
|
TIMER_ID_RTC,
|
||||||
|
TIMER_ID_SD,
|
||||||
TIMER_ID_USB,
|
TIMER_ID_USB,
|
||||||
TIMER_ID_WRITEBACK,
|
TIMER_ID_WRITEBACK,
|
||||||
__TIMER_ID_COUNT
|
__TIMER_ID_COUNT
|
||||||
} timer_id_t;
|
} timer_id_t;
|
||||||
|
|
||||||
|
|
||||||
uint32_t timer_get (timer_id_t id);
|
void timer_countdown_start (timer_id_t id, uint32_t value_ms);
|
||||||
void timer_set (timer_id_t id, uint32_t ticks);
|
void timer_countdown_abort (timer_id_t id);
|
||||||
|
bool timer_countdown_elapsed (timer_id_t id);
|
||||||
|
|
||||||
void timer_init (void);
|
void timer_init (void);
|
||||||
void timer_update (void);
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -312,7 +312,7 @@ void update_perform (void) {
|
|||||||
fpga_mem_read(parameters.mcu_address - 4, sizeof(length), (uint8_t *) (&length));
|
fpga_mem_read(parameters.mcu_address - 4, sizeof(length), (uint8_t *) (&length));
|
||||||
if (mcu_update(parameters.mcu_address, length)) {
|
if (mcu_update(parameters.mcu_address, length)) {
|
||||||
update_status_notify(UPDATE_STATUS_ERROR);
|
update_status_notify(UPDATE_STATUS_ERROR);
|
||||||
while (1);
|
while (true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -321,7 +321,7 @@ void update_perform (void) {
|
|||||||
fpga_mem_read(parameters.fpga_address - 4, sizeof(length), (uint8_t *) (&length));
|
fpga_mem_read(parameters.fpga_address - 4, sizeof(length), (uint8_t *) (&length));
|
||||||
if (vendor_update(parameters.fpga_address, length) != VENDOR_OK) {
|
if (vendor_update(parameters.fpga_address, length) != VENDOR_OK) {
|
||||||
update_status_notify(UPDATE_STATUS_ERROR);
|
update_status_notify(UPDATE_STATUS_ERROR);
|
||||||
while (1);
|
while (true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -330,7 +330,7 @@ void update_perform (void) {
|
|||||||
fpga_mem_read(parameters.bootloader_address - 4, sizeof(length), (uint8_t *) (&length));
|
fpga_mem_read(parameters.bootloader_address - 4, sizeof(length), (uint8_t *) (&length));
|
||||||
if (bootloader_update(parameters.bootloader_address, length)) {
|
if (bootloader_update(parameters.bootloader_address, length)) {
|
||||||
update_status_notify(UPDATE_STATUS_ERROR);
|
update_status_notify(UPDATE_STATUS_ERROR);
|
||||||
while (1);
|
while (true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
#include "app.h"
|
|
||||||
#include "cfg.h"
|
#include "cfg.h"
|
||||||
#include "cic.h"
|
#include "cic.h"
|
||||||
#include "dd.h"
|
#include "dd.h"
|
||||||
#include "flash.h"
|
#include "flash.h"
|
||||||
#include "fpga.h"
|
#include "fpga.h"
|
||||||
|
#include "hw.h"
|
||||||
#include "rtc.h"
|
#include "rtc.h"
|
||||||
#include "timer.h"
|
#include "timer.h"
|
||||||
#include "update.h"
|
#include "update.h"
|
||||||
@ -12,15 +12,18 @@
|
|||||||
#include "writeback.h"
|
#include "writeback.h"
|
||||||
|
|
||||||
|
|
||||||
#define BOOTLOADER_ADDRESS (0x04E00000UL)
|
#define BOOTLOADER_ADDRESS (0x04E00000UL)
|
||||||
#define BOOTLOADER_LENGTH (1920 * 1024)
|
#define BOOTLOADER_LENGTH (1920 * 1024)
|
||||||
|
|
||||||
#define MEMORY_LENGTH (0x05002980UL)
|
#define MEMORY_LENGTH (0x05002980UL)
|
||||||
|
|
||||||
#define RX_FLUSH_ADDRESS (0x07F00000UL)
|
#define RX_FLUSH_ADDRESS (0x07F00000UL)
|
||||||
#define RX_FLUSH_LENGTH (1 * 1024 * 1024)
|
#define RX_FLUSH_LENGTH (1 * 1024 * 1024)
|
||||||
|
|
||||||
#define DEBUG_WRITE_TIMEOUT_TICKS (100)
|
#define DEBUG_WRITE_TIMEOUT_MS (1000)
|
||||||
|
|
||||||
|
#define DIAGNOSTIC_DATA_MARKER (1 << 31)
|
||||||
|
#define DIAGNOSTIC_DATA_VERSION (1)
|
||||||
|
|
||||||
|
|
||||||
enum rx_state {
|
enum rx_state {
|
||||||
@ -175,7 +178,7 @@ static void usb_rx_process (void) {
|
|||||||
p.response_info.dma_length = 0;
|
p.response_info.dma_length = 0;
|
||||||
p.response_info.done_callback = NULL;
|
p.response_info.done_callback = NULL;
|
||||||
if (p.rx_cmd == 'U') {
|
if (p.rx_cmd == 'U') {
|
||||||
timer_set(TIMER_ID_USB, DEBUG_WRITE_TIMEOUT_TICKS);
|
timer_countdown_start(TIMER_ID_USB, DEBUG_WRITE_TIMEOUT_MS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -311,9 +314,9 @@ static void usb_rx_process (void) {
|
|||||||
p.read_length -= length;
|
p.read_length -= length;
|
||||||
p.read_address += length;
|
p.read_address += length;
|
||||||
p.read_ready = true;
|
p.read_ready = true;
|
||||||
timer_set(TIMER_ID_USB, DEBUG_WRITE_TIMEOUT_TICKS);
|
timer_countdown_start(TIMER_ID_USB, DEBUG_WRITE_TIMEOUT_MS);
|
||||||
}
|
}
|
||||||
} else if (timer_get(TIMER_ID_USB) == 0) {
|
} else if (timer_countdown_elapsed(TIMER_ID_USB)) {
|
||||||
p.rx_state = RX_STATE_FLUSH;
|
p.rx_state = RX_STATE_FLUSH;
|
||||||
p.flush_packet = true;
|
p.flush_packet = true;
|
||||||
}
|
}
|
||||||
@ -382,12 +385,19 @@ static void usb_rx_process (void) {
|
|||||||
p.response_info.data[1] = fpga_reg_get(REG_DEBUG_1);
|
p.response_info.data[1] = fpga_reg_get(REG_DEBUG_1);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case '%':
|
case '%': {
|
||||||
|
uint16_t voltage;
|
||||||
|
int16_t temperature;
|
||||||
|
hw_adc_read_voltage_temperature(&voltage, &temperature);
|
||||||
p.rx_state = RX_STATE_IDLE;
|
p.rx_state = RX_STATE_IDLE;
|
||||||
p.response_pending = true;
|
p.response_pending = true;
|
||||||
p.response_info.data_length = 16;
|
p.response_info.data_length = 16;
|
||||||
app_get_stack_usage(p.response_info.data);
|
p.response_info.data[0] = (DIAGNOSTIC_DATA_MARKER | DIAGNOSTIC_DATA_VERSION);
|
||||||
|
p.response_info.data[1] = (uint32_t) (voltage);
|
||||||
|
p.response_info.data[2] = (uint32_t) (temperature);
|
||||||
|
p.response_info.data[3] = 0;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
p.rx_state = RX_STATE_IDLE;
|
p.rx_state = RX_STATE_IDLE;
|
||||||
@ -521,6 +531,7 @@ bool usb_enqueue_packet (usb_tx_info_t *info) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool usb_prepare_read (uint32_t *args) {
|
bool usb_prepare_read (uint32_t *args) {
|
||||||
if (!p.read_ready) {
|
if (!p.read_ready) {
|
||||||
return false;
|
return false;
|
||||||
@ -543,6 +554,7 @@ void usb_get_read_info (uint32_t *args) {
|
|||||||
args[0] |= (scr & USB_SCR_PWRSAV) ? (1 << 29) : 0;
|
args[0] |= (scr & USB_SCR_PWRSAV) ? (1 << 29) : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void usb_init (void) {
|
void usb_init (void) {
|
||||||
fpga_reg_set(REG_USB_DMA_SCR, DMA_SCR_STOP);
|
fpga_reg_set(REG_USB_DMA_SCR, DMA_SCR_STOP);
|
||||||
fpga_reg_set(REG_USB_SCR, USB_SCR_FIFO_FLUSH);
|
fpga_reg_set(REG_USB_SCR, USB_SCR_FIFO_FLUSH);
|
||||||
@ -563,6 +575,7 @@ void usb_init (void) {
|
|||||||
usb_rx_cmd_counter = 0;
|
usb_rx_cmd_counter = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void usb_process (void) {
|
void usb_process (void) {
|
||||||
uint32_t scr = fpga_reg_get(REG_USB_SCR);
|
uint32_t scr = fpga_reg_get(REG_USB_SCR);
|
||||||
if (scr & (USB_SCR_PWRSAV | USB_SCR_RESET_STATE | USB_SCR_RESET_PENDING)) {
|
if (scr & (USB_SCR_PWRSAV | USB_SCR_RESET_STATE | USB_SCR_RESET_PENDING)) {
|
||||||
|
@ -29,9 +29,12 @@ typedef struct usb_tx_info {
|
|||||||
|
|
||||||
void usb_create_packet (usb_tx_info_t *info, usb_packet_cmd_e cmd);
|
void usb_create_packet (usb_tx_info_t *info, usb_packet_cmd_e cmd);
|
||||||
bool usb_enqueue_packet (usb_tx_info_t *info);
|
bool usb_enqueue_packet (usb_tx_info_t *info);
|
||||||
|
|
||||||
bool usb_prepare_read (uint32_t *args);
|
bool usb_prepare_read (uint32_t *args);
|
||||||
void usb_get_read_info (uint32_t *args);
|
void usb_get_read_info (uint32_t *args);
|
||||||
|
|
||||||
void usb_init (void);
|
void usb_init (void);
|
||||||
|
|
||||||
void usb_process (void);
|
void usb_process (void);
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,21 +1,25 @@
|
|||||||
#include "cfg.h"
|
#include "cfg.h"
|
||||||
#include "fpga.h"
|
#include "fpga.h"
|
||||||
|
#include "led.h"
|
||||||
#include "sd.h"
|
#include "sd.h"
|
||||||
#include "timer.h"
|
#include "timer.h"
|
||||||
#include "usb.h"
|
#include "usb.h"
|
||||||
#include "writeback.h"
|
#include "writeback.h"
|
||||||
|
|
||||||
|
|
||||||
#define SAVE_MAX_SECTOR_COUNT (256)
|
#define SAVE_MAX_SECTOR_COUNT (256)
|
||||||
#define EEPROM_ADDRESS (0x05002000)
|
|
||||||
#define SRAM_FLASHRAM_ADDRESS (0x03FE0000)
|
#define EEPROM_ADDRESS (0x05002000)
|
||||||
#define EEPROM_4K_LENGTH (512)
|
#define SRAM_FLASHRAM_ADDRESS (0x03FE0000)
|
||||||
#define EEPROM_16K_LENGTH (2048)
|
|
||||||
#define SRAM_LENGTH (32 * 1024)
|
#define EEPROM_4K_LENGTH (512)
|
||||||
#define FLASHRAM_LENGTH (128 * 1024)
|
#define EEPROM_16K_LENGTH (2048)
|
||||||
#define SRAM_BANKED_LENGTH (3 * 32 * 1024)
|
#define SRAM_LENGTH (32 * 1024)
|
||||||
#define SRAM_1M_LENGTH (128 * 1024)
|
#define FLASHRAM_LENGTH (128 * 1024)
|
||||||
#define WRITEBACK_DELAY_TICKS (100)
|
#define SRAM_BANKED_LENGTH (3 * 32 * 1024)
|
||||||
|
#define SRAM_1M_LENGTH (128 * 1024)
|
||||||
|
|
||||||
|
#define WRITEBACK_DELAY_MS (1000)
|
||||||
|
|
||||||
|
|
||||||
struct process {
|
struct process {
|
||||||
@ -78,9 +82,14 @@ static void writeback_save_to_sd (void) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(sd_optimize_sectors(address, p.sectors, length / SD_SECTOR_SIZE, sd_write_sectors)) {
|
bool error = sd_optimize_sectors(address, p.sectors, (length / SD_SECTOR_SIZE), sd_write_sectors);
|
||||||
|
|
||||||
|
if (error) {
|
||||||
writeback_disable();
|
writeback_disable();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
led_activity_pulse();
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool writeback_save_to_usb (void) {
|
static bool writeback_save_to_usb (void) {
|
||||||
@ -100,7 +109,13 @@ static bool writeback_save_to_usb (void) {
|
|||||||
packet_info.data[0] = save;
|
packet_info.data[0] = save;
|
||||||
packet_info.dma_length = length;
|
packet_info.dma_length = length;
|
||||||
packet_info.dma_address = address;
|
packet_info.dma_address = address;
|
||||||
return usb_enqueue_packet(&packet_info);
|
bool enqueued = usb_enqueue_packet(&packet_info);
|
||||||
|
|
||||||
|
if (enqueued) {
|
||||||
|
led_activity_pulse();
|
||||||
|
}
|
||||||
|
|
||||||
|
return enqueued;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -111,6 +126,7 @@ void writeback_load_sector_table (uint32_t address) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void writeback_enable (writeback_mode_t mode) {
|
void writeback_enable (writeback_mode_t mode) {
|
||||||
p.enabled = true;
|
p.enabled = true;
|
||||||
p.pending = false;
|
p.pending = false;
|
||||||
@ -121,13 +137,14 @@ void writeback_enable (writeback_mode_t mode) {
|
|||||||
void writeback_disable (void) {
|
void writeback_disable (void) {
|
||||||
p.enabled = false;
|
p.enabled = false;
|
||||||
p.pending = false;
|
p.pending = false;
|
||||||
timer_set(TIMER_ID_WRITEBACK, 0);
|
timer_countdown_abort(TIMER_ID_WRITEBACK);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool writeback_pending (void) {
|
bool writeback_pending (void) {
|
||||||
return p.enabled && p.pending;
|
return p.enabled && p.pending;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void writeback_init (void) {
|
void writeback_init (void) {
|
||||||
p.enabled = false;
|
p.enabled = false;
|
||||||
p.pending = false;
|
p.pending = false;
|
||||||
@ -137,6 +154,7 @@ void writeback_init (void) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void writeback_process (void) {
|
void writeback_process (void) {
|
||||||
if (p.enabled && (p.mode == WRITEBACK_SD) && !sd_card_is_inserted()) {
|
if (p.enabled && (p.mode == WRITEBACK_SD) && !sd_card_is_inserted()) {
|
||||||
writeback_disable();
|
writeback_disable();
|
||||||
@ -144,24 +162,27 @@ void writeback_process (void) {
|
|||||||
|
|
||||||
if (p.enabled) {
|
if (p.enabled) {
|
||||||
uint16_t save_count = fpga_reg_get(REG_SAVE_COUNT);
|
uint16_t save_count = fpga_reg_get(REG_SAVE_COUNT);
|
||||||
|
|
||||||
if (save_count != p.last_save_count) {
|
if (save_count != p.last_save_count) {
|
||||||
p.pending = true;
|
p.pending = true;
|
||||||
p.last_save_count = save_count;
|
p.last_save_count = save_count;
|
||||||
timer_set(TIMER_ID_WRITEBACK, WRITEBACK_DELAY_TICKS);
|
timer_countdown_start(TIMER_ID_WRITEBACK, WRITEBACK_DELAY_MS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (p.pending && (timer_get(TIMER_ID_WRITEBACK) == 0)) {
|
if (p.pending && timer_countdown_elapsed(TIMER_ID_WRITEBACK)) {
|
||||||
switch (p.mode) {
|
switch (p.mode) {
|
||||||
case WRITEBACK_SD:
|
case WRITEBACK_SD:
|
||||||
writeback_save_to_sd();
|
writeback_save_to_sd();
|
||||||
p.pending = false;
|
p.pending = false;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case WRITEBACK_USB:
|
case WRITEBACK_USB:
|
||||||
if (writeback_save_to_usb()) {
|
if (writeback_save_to_usb()) {
|
||||||
p.pending = false;
|
p.pending = false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
writeback_disable();
|
writeback_disable();
|
||||||
break;
|
break;
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
|
||||||
#define WRITEBACK_SECTOR_TABLE_SIZE (1024)
|
#define WRITEBACK_SECTOR_TABLE_SIZE (1024)
|
||||||
|
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
@ -16,10 +16,13 @@ typedef enum {
|
|||||||
|
|
||||||
|
|
||||||
void writeback_load_sector_table (uint32_t address);
|
void writeback_load_sector_table (uint32_t address);
|
||||||
|
|
||||||
void writeback_enable (writeback_mode_t mode);
|
void writeback_enable (writeback_mode_t mode);
|
||||||
void writeback_disable (void);
|
void writeback_disable (void);
|
||||||
bool writeback_pending (void);
|
bool writeback_pending (void);
|
||||||
|
|
||||||
void writeback_init (void);
|
void writeback_init (void);
|
||||||
|
|
||||||
void writeback_process (void);
|
void writeback_process (void);
|
||||||
|
|
||||||
|
|
||||||
|
958
sw/deployer/Cargo.lock
generated
958
sw/deployer/Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@ -20,8 +20,8 @@ include-flate = { version = "0.2.0", features = ["stable"] }
|
|||||||
md5 = "0.7.0"
|
md5 = "0.7.0"
|
||||||
panic-message = "0.3.0"
|
panic-message = "0.3.0"
|
||||||
rust-ini = "0.18.0"
|
rust-ini = "0.18.0"
|
||||||
serial2 = "0.1.7"
|
serial2 = "0.2.17"
|
||||||
serialport = "4.2.0"
|
serialport = "4.3.0"
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
lto = true
|
lto = true
|
||||||
|
@ -166,6 +166,20 @@ const MAX_PACKET_LENGTH: usize = 8 * 1024 * 1024;
|
|||||||
const SUPPORTED_USB_PROTOCOL_VERSION: u16 = 2;
|
const SUPPORTED_USB_PROTOCOL_VERSION: u16 = 2;
|
||||||
|
|
||||||
impl Handler {
|
impl Handler {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
let (line_tx, line_rx) = channel::<String>();
|
||||||
|
let external_line_tx = line_tx.clone();
|
||||||
|
|
||||||
|
spawn(move || stdin_thread(line_tx));
|
||||||
|
|
||||||
|
Handler {
|
||||||
|
header: None,
|
||||||
|
line_rx,
|
||||||
|
external_line_tx,
|
||||||
|
encoding: Encoding::UTF8,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn set_text_encoding(&mut self, encoding: Encoding) {
|
pub fn set_text_encoding(&mut self, encoding: Encoding) {
|
||||||
self.encoding = encoding;
|
self.encoding = encoding;
|
||||||
}
|
}
|
||||||
@ -391,20 +405,6 @@ impl Handler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new() -> Handler {
|
|
||||||
let (line_tx, line_rx) = channel::<String>();
|
|
||||||
let external_line_tx = line_tx.clone();
|
|
||||||
|
|
||||||
spawn(move || stdin_thread(line_tx));
|
|
||||||
|
|
||||||
Handler {
|
|
||||||
header: None,
|
|
||||||
line_rx,
|
|
||||||
external_line_tx,
|
|
||||||
encoding: Encoding::UTF8,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn load_file(path: &str) -> Result<Vec<u8>, String> {
|
fn load_file(path: &str) -> Result<Vec<u8>, String> {
|
||||||
if path.len() == 0 {
|
if path.len() == 0 {
|
||||||
return Err(format!("Couldn't open file: Specified path is empty"));
|
return Err(format!("Couldn't open file: Specified path is empty"));
|
||||||
|
@ -417,7 +417,7 @@ fn handle_64dd_command(connection: Connection, args: &_64DDArgs) -> Result<(), s
|
|||||||
|
|
||||||
let mut sc64 = init_sc64(connection, true)?;
|
let mut sc64 = init_sc64(connection, true)?;
|
||||||
|
|
||||||
let mut debug_handler = debug::new();
|
let mut debug_handler = debug::Handler::new();
|
||||||
|
|
||||||
println!(
|
println!(
|
||||||
"{}\n{}\n{}\n{}",
|
"{}\n{}\n{}\n{}",
|
||||||
@ -627,7 +627,7 @@ fn handle_64dd_command(connection: Connection, args: &_64DDArgs) -> Result<(), s
|
|||||||
fn handle_debug_command(connection: Connection, args: &DebugArgs) -> Result<(), sc64::Error> {
|
fn handle_debug_command(connection: Connection, args: &DebugArgs) -> Result<(), sc64::Error> {
|
||||||
let mut sc64 = init_sc64(connection, true)?;
|
let mut sc64 = init_sc64(connection, true)?;
|
||||||
|
|
||||||
let mut debug_handler = debug::new();
|
let mut debug_handler = debug::Handler::new();
|
||||||
|
|
||||||
if args.euc_jp {
|
if args.euc_jp {
|
||||||
debug_handler.set_text_encoding(debug::Encoding::EUCJP);
|
debug_handler.set_text_encoding(debug::Encoding::EUCJP);
|
||||||
@ -738,7 +738,7 @@ fn handle_info_command(connection: Connection) -> Result<(), sc64::Error> {
|
|||||||
println!(" LED blink: {}", state.led_enable);
|
println!(" LED blink: {}", state.led_enable);
|
||||||
println!(" IS-Viewer 64 offset: 0x{:08X}", state.isv_address);
|
println!(" IS-Viewer 64 offset: 0x{:08X}", state.isv_address);
|
||||||
println!(" FPGA debug data: {}", state.fpga_debug_data);
|
println!(" FPGA debug data: {}", state.fpga_debug_data);
|
||||||
println!(" MCU stack usage: {}", state.mcu_stack_usage);
|
println!(" Diagnostic data: {}", state.diagnostic_data);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -859,7 +859,7 @@ fn handle_server_command(connection: Connection, args: &ServerArgs) -> Result<()
|
|||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
sc64::run_server(port, args.address.clone(), |event| match event {
|
sc64::server::run(port, args.address.clone(), |event| match event {
|
||||||
sc64::ServerEvent::Listening(address) => {
|
sc64::ServerEvent::Listening(address) => {
|
||||||
println!(
|
println!(
|
||||||
"{}: Listening on address [{}]",
|
"{}: Listening on address [{}]",
|
||||||
@ -895,8 +895,8 @@ fn handle_server_command(connection: Connection, args: &ServerArgs) -> Result<()
|
|||||||
|
|
||||||
fn init_sc64(connection: Connection, check_firmware: bool) -> Result<sc64::SC64, sc64::Error> {
|
fn init_sc64(connection: Connection, check_firmware: bool) -> Result<sc64::SC64, sc64::Error> {
|
||||||
let mut sc64 = match connection {
|
let mut sc64 = match connection {
|
||||||
Connection::Local(port) => sc64::new_local(port),
|
Connection::Local(port) => sc64::SC64::open_local(port),
|
||||||
Connection::Remote(remote) => sc64::new_remote(remote),
|
Connection::Remote(remote) => sc64::SC64::open_remote(remote),
|
||||||
}?;
|
}?;
|
||||||
|
|
||||||
if check_firmware {
|
if check_firmware {
|
||||||
|
@ -2,7 +2,7 @@ mod cic;
|
|||||||
mod error;
|
mod error;
|
||||||
pub mod firmware;
|
pub mod firmware;
|
||||||
mod link;
|
mod link;
|
||||||
mod server;
|
pub mod server;
|
||||||
mod time;
|
mod time;
|
||||||
mod types;
|
mod types;
|
||||||
|
|
||||||
@ -12,7 +12,7 @@ pub use self::{
|
|||||||
server::ServerEvent,
|
server::ServerEvent,
|
||||||
types::{
|
types::{
|
||||||
BootMode, ButtonMode, ButtonState, CicSeed, DataPacket, DdDiskState, DdDriveType, DdMode,
|
BootMode, ButtonMode, ButtonState, CicSeed, DataPacket, DdDiskState, DdDriveType, DdMode,
|
||||||
DebugPacket, DiskPacket, DiskPacketKind, FpgaDebugData, McuStackUsage, SaveType,
|
DebugPacket, DiagnosticData, DiskPacket, DiskPacketKind, FpgaDebugData, SaveType,
|
||||||
SaveWriteback, Switch, TvType,
|
SaveWriteback, Switch, TvType,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@ -55,7 +55,7 @@ pub struct DeviceState {
|
|||||||
pub led_enable: Switch,
|
pub led_enable: Switch,
|
||||||
pub datetime: DateTime<Local>,
|
pub datetime: DateTime<Local>,
|
||||||
pub fpga_debug_data: FpgaDebugData,
|
pub fpga_debug_data: FpgaDebugData,
|
||||||
pub mcu_stack_usage: McuStackUsage,
|
pub diagnostic_data: DiagnosticData,
|
||||||
}
|
}
|
||||||
|
|
||||||
const SC64_V2_IDENTIFIER: &[u8; 4] = b"SCv2";
|
const SC64_V2_IDENTIFIER: &[u8; 4] = b"SCv2";
|
||||||
@ -350,7 +350,7 @@ impl SC64 {
|
|||||||
Ok(u32::from_be_bytes(data[0..4].try_into().unwrap()).try_into()?)
|
Ok(u32::from_be_bytes(data[0..4].try_into().unwrap()).try_into()?)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn command_debug_get(&mut self) -> Result<FpgaDebugData, Error> {
|
fn command_fpga_debug_data_get(&mut self) -> Result<FpgaDebugData, Error> {
|
||||||
let data = self.link.execute_command(&Command {
|
let data = self.link.execute_command(&Command {
|
||||||
id: b'?',
|
id: b'?',
|
||||||
args: [0, 0],
|
args: [0, 0],
|
||||||
@ -359,7 +359,7 @@ impl SC64 {
|
|||||||
Ok(data.try_into()?)
|
Ok(data.try_into()?)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn command_stack_usage_get(&mut self) -> Result<McuStackUsage, Error> {
|
fn command_diagnostic_data_get(&mut self) -> Result<DiagnosticData, Error> {
|
||||||
let data = self.link.execute_command(&Command {
|
let data = self.link.execute_command(&Command {
|
||||||
id: b'%',
|
id: b'%',
|
||||||
args: [0, 0],
|
args: [0, 0],
|
||||||
@ -557,8 +557,8 @@ impl SC64 {
|
|||||||
rom_extended_enable: get_config!(self, RomExtendedEnable)?,
|
rom_extended_enable: get_config!(self, RomExtendedEnable)?,
|
||||||
led_enable: get_setting!(self, LedEnable)?,
|
led_enable: get_setting!(self, LedEnable)?,
|
||||||
datetime: self.get_datetime()?,
|
datetime: self.get_datetime()?,
|
||||||
fpga_debug_data: self.command_debug_get()?,
|
fpga_debug_data: self.command_fpga_debug_data_get()?,
|
||||||
mcu_stack_usage: self.command_stack_usage_get()?,
|
diagnostic_data: self.command_diagnostic_data_get()?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -787,36 +787,25 @@ impl SC64 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_local(port: Option<String>) -> Result<SC64, Error> {
|
impl SC64 {
|
||||||
let port = if let Some(port) = port {
|
pub fn open_local(port: Option<String>) -> Result<Self, Error> {
|
||||||
port
|
let port = if let Some(port) = port {
|
||||||
} else {
|
port
|
||||||
list_local_devices()?[0].port.clone()
|
} else {
|
||||||
};
|
list_local_devices()?[0].port.clone()
|
||||||
let mut sc64 = SC64 {
|
};
|
||||||
link: link::new_local(&port)?,
|
let mut sc64 = SC64 {
|
||||||
};
|
link: link::new_local(&port)?,
|
||||||
sc64.check_device()?;
|
};
|
||||||
Ok(sc64)
|
sc64.check_device()?;
|
||||||
}
|
Ok(sc64)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn new_remote(address: String) -> Result<SC64, Error> {
|
pub fn open_remote(address: String) -> Result<Self, Error> {
|
||||||
let mut sc64 = SC64 {
|
let mut sc64 = SC64 {
|
||||||
link: link::new_remote(&address)?,
|
link: link::new_remote(&address)?,
|
||||||
};
|
};
|
||||||
sc64.check_device()?;
|
sc64.check_device()?;
|
||||||
Ok(sc64)
|
Ok(sc64)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_server(
|
|
||||||
port: Option<String>,
|
|
||||||
address: String,
|
|
||||||
event_callback: fn(ServerEvent),
|
|
||||||
) -> Result<(), Error> {
|
|
||||||
let port = if let Some(port) = port {
|
|
||||||
port
|
|
||||||
} else {
|
|
||||||
list_local_devices()?[0].port.clone()
|
|
||||||
};
|
|
||||||
server::run_server(&port, address, event_callback)
|
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use super::{
|
use super::{
|
||||||
error::Error,
|
error::Error,
|
||||||
link::{new_serial, Command, DataType, Packet, Response, Serial},
|
link::{list_local_devices, new_serial, Command, DataType, Packet, Response, Serial},
|
||||||
};
|
};
|
||||||
use std::{
|
use std::{
|
||||||
collections::VecDeque,
|
collections::VecDeque,
|
||||||
@ -22,11 +22,16 @@ pub enum ServerEvent {
|
|||||||
Err(String),
|
Err(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_server(
|
pub fn run(
|
||||||
port: &str,
|
port: Option<String>,
|
||||||
address: String,
|
address: String,
|
||||||
event_callback: fn(ServerEvent),
|
event_callback: fn(ServerEvent),
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
|
let port = if let Some(port) = port {
|
||||||
|
port
|
||||||
|
} else {
|
||||||
|
list_local_devices()?[0].port.clone()
|
||||||
|
};
|
||||||
let listener = TcpListener::bind(address)?;
|
let listener = TcpListener::bind(address)?;
|
||||||
let listening_address = listener.local_addr()?;
|
let listening_address = listener.local_addr()?;
|
||||||
event_callback(ServerEvent::Listening(listening_address.to_string()));
|
event_callback(ServerEvent::Listening(listening_address.to_string()));
|
||||||
@ -36,7 +41,7 @@ pub fn run_server(
|
|||||||
Ok(mut stream) => {
|
Ok(mut stream) => {
|
||||||
let peer = stream.peer_addr()?.to_string();
|
let peer = stream.peer_addr()?.to_string();
|
||||||
event_callback(ServerEvent::Connected(peer.clone()));
|
event_callback(ServerEvent::Connected(peer.clone()));
|
||||||
match server_accept_connection(port, &mut stream) {
|
match server_accept_connection(port.clone(), &mut stream) {
|
||||||
Ok(()) => event_callback(ServerEvent::Disconnected(peer.clone())),
|
Ok(()) => event_callback(ServerEvent::Disconnected(peer.clone())),
|
||||||
Err(error) => event_callback(ServerEvent::Err(error.to_string())),
|
Err(error) => event_callback(ServerEvent::Err(error.to_string())),
|
||||||
}
|
}
|
||||||
@ -58,14 +63,14 @@ enum Event {
|
|||||||
Closed(Option<Error>),
|
Closed(Option<Error>),
|
||||||
}
|
}
|
||||||
|
|
||||||
fn server_accept_connection(port: &str, stream: &mut TcpStream) -> Result<(), Error> {
|
fn server_accept_connection(port: String, stream: &mut TcpStream) -> Result<(), Error> {
|
||||||
let (event_sender, event_receiver) = channel::<Event>();
|
let (event_sender, event_receiver) = channel::<Event>();
|
||||||
let exit_flag = Arc::new(AtomicBool::new(false));
|
let exit_flag = Arc::new(AtomicBool::new(false));
|
||||||
|
|
||||||
let mut stream_writer = BufWriter::new(stream.try_clone()?);
|
let mut stream_writer = BufWriter::new(stream.try_clone()?);
|
||||||
let mut stream_reader = stream.try_clone()?;
|
let mut stream_reader = stream.try_clone()?;
|
||||||
|
|
||||||
let serial = Arc::new(new_serial(port)?);
|
let serial = Arc::new(new_serial(&port)?);
|
||||||
let serial_writer = serial.clone();
|
let serial_writer = serial.clone();
|
||||||
let serial_reader = serial.clone();
|
let serial_reader = serial.clone();
|
||||||
|
|
||||||
|
@ -828,37 +828,81 @@ impl Display for FpgaDebugData {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct McuStackUsage {
|
pub struct DiagnosticDataV0 {
|
||||||
pub cic: u32,
|
pub cic: u32,
|
||||||
pub rtc: u32,
|
pub rtc: u32,
|
||||||
pub led: u32,
|
pub led: u32,
|
||||||
pub gvr: u32,
|
pub gvr: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<Vec<u8>> for McuStackUsage {
|
pub struct DiagnosticDataV1 {
|
||||||
|
pub voltage: f32,
|
||||||
|
pub temperature: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum DiagnosticData {
|
||||||
|
V0(DiagnosticDataV0),
|
||||||
|
V1(DiagnosticDataV1),
|
||||||
|
Unknown,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<Vec<u8>> for DiagnosticData {
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> {
|
fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> {
|
||||||
if value.len() != 16 {
|
if value.len() < 4 {
|
||||||
return Err(Error::new("Invalid data length for MCU stack usage"));
|
return Err(Error::new("Invalid data length for diagnostic data"));
|
||||||
|
}
|
||||||
|
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),
|
||||||
}
|
}
|
||||||
Ok(McuStackUsage {
|
|
||||||
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()),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for McuStackUsage {
|
impl Display for DiagnosticData {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
if self.cic > 0 {
|
match self {
|
||||||
f.write_fmt(format_args!("CIC: {}, ", self.cic))?;
|
DiagnosticData::V0(d) => {
|
||||||
|
if d.cic > 0 {
|
||||||
|
f.write_fmt(format_args!("CIC: {}, ", d.cic))?;
|
||||||
|
}
|
||||||
|
f.write_fmt(format_args!(
|
||||||
|
"RTC: {}, LED: {}, 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"),
|
||||||
}
|
}
|
||||||
f.write_fmt(format_args!(
|
|
||||||
"RTC: {}, LED: {}, GVR: {}",
|
|
||||||
self.rtc, self.led, self.gvr
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -874,7 +918,7 @@ macro_rules! get_config {
|
|||||||
|
|
||||||
macro_rules! get_setting {
|
macro_rules! get_setting {
|
||||||
($sc64:ident, $setting:ident) => {{
|
($sc64:ident, $setting:ident) => {{
|
||||||
// Note: remove 'allow(irrefutable_let_patterns)' below when more settings are added
|
// NOTE: remove 'allow(irrefutable_let_patterns)' below when more settings are added
|
||||||
#[allow(irrefutable_let_patterns)]
|
#[allow(irrefutable_let_patterns)]
|
||||||
if let Setting::$setting(value) = $sc64.command_setting_get(SettingId::$setting)? {
|
if let Setting::$setting(value) = $sc64.command_setting_get(SettingId::$setting)? {
|
||||||
Ok(value)
|
Ok(value)
|
||||||
|
@ -204,9 +204,16 @@ class STM32Bootloader:
|
|||||||
|
|
||||||
__connected = False
|
__connected = False
|
||||||
|
|
||||||
def __init__(self, write: Callable[[bytes], None], read: Callable[[int], bytes], progress: Callable[[int, int, str], None]):
|
def __init__(
|
||||||
|
self,
|
||||||
|
write: Callable[[bytes], None],
|
||||||
|
read: Callable[[int], bytes],
|
||||||
|
flush: Callable[[None], None],
|
||||||
|
progress: Callable[[int, int, str], None]
|
||||||
|
):
|
||||||
self.__write = write
|
self.__write = write
|
||||||
self.__read = read
|
self.__read = read
|
||||||
|
self.__flush = flush
|
||||||
self.__progress = progress
|
self.__progress = progress
|
||||||
|
|
||||||
def __append_xor(self, data: bytes) -> bytes:
|
def __append_xor(self, data: bytes) -> bytes:
|
||||||
@ -217,7 +224,7 @@ class STM32Bootloader:
|
|||||||
|
|
||||||
def __check_ack(self) -> None:
|
def __check_ack(self) -> None:
|
||||||
response = self.__read(1)
|
response = self.__read(1)
|
||||||
if (response == None):
|
if (len(response) != 1):
|
||||||
raise STM32BootloaderException('No ACK/NACK byte received')
|
raise STM32BootloaderException('No ACK/NACK byte received')
|
||||||
if (response == self.__NACK):
|
if (response == self.__NACK):
|
||||||
raise STM32BootloaderException('NACK byte received')
|
raise STM32BootloaderException('NACK byte received')
|
||||||
@ -228,18 +235,22 @@ class STM32Bootloader:
|
|||||||
if (len(cmd) != 1):
|
if (len(cmd) != 1):
|
||||||
raise ValueError('Command must contain only one byte')
|
raise ValueError('Command must contain only one byte')
|
||||||
self.__write(self.__append_xor(cmd))
|
self.__write(self.__append_xor(cmd))
|
||||||
|
self.__flush()
|
||||||
self.__check_ack()
|
self.__check_ack()
|
||||||
|
|
||||||
def __data_write(self, data: bytes) -> None:
|
def __data_write(self, data: bytes) -> None:
|
||||||
self.__write(self.__append_xor(data))
|
self.__write(self.__append_xor(data))
|
||||||
|
self.__flush()
|
||||||
self.__check_ack()
|
self.__check_ack()
|
||||||
|
|
||||||
def __data_read(self) -> bytes:
|
def __data_read(self) -> bytes:
|
||||||
length = self.__read(1)
|
length = self.__read(1)
|
||||||
if (len(length) != 1):
|
if (len(length) != 1):
|
||||||
raise STM32BootloaderException('Did not receive length byte')
|
raise STM32BootloaderException('Did not receive length byte')
|
||||||
length = length[0]
|
length = (length[0] + 1)
|
||||||
data = self.__read(length + 1)
|
data = self.__read(length)
|
||||||
|
if (len(data) != length):
|
||||||
|
raise STM32BootloaderException('Did not receive requested data bytes')
|
||||||
self.__check_ack()
|
self.__check_ack()
|
||||||
return data
|
return data
|
||||||
|
|
||||||
@ -253,7 +264,10 @@ class STM32Bootloader:
|
|||||||
self.__cmd_send(b'\x11')
|
self.__cmd_send(b'\x11')
|
||||||
self.__data_write(address.to_bytes(4, byteorder='big'))
|
self.__data_write(address.to_bytes(4, byteorder='big'))
|
||||||
self.__data_write(bytes([length - 1]))
|
self.__data_write(bytes([length - 1]))
|
||||||
return self.__read(length)
|
data = self.__read(length)
|
||||||
|
if (len(data) != length):
|
||||||
|
raise STM32BootloaderException(f'Did not receive requested memory bytes')
|
||||||
|
return data
|
||||||
|
|
||||||
def __go(self, address: int) -> None:
|
def __go(self, address: int) -> None:
|
||||||
self.__cmd_send(b'\x21')
|
self.__cmd_send(b'\x21')
|
||||||
@ -288,8 +302,12 @@ class STM32Bootloader:
|
|||||||
|
|
||||||
def connect(self, id: int) -> None:
|
def connect(self, id: int) -> None:
|
||||||
if (not self.__connected):
|
if (not self.__connected):
|
||||||
self.__write(self.__INIT)
|
try:
|
||||||
self.__check_ack()
|
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
|
self.__connected = True
|
||||||
dev_id = self.__get_id()
|
dev_id = self.__get_id()
|
||||||
if (dev_id != id):
|
if (dev_id != id):
|
||||||
@ -339,9 +357,16 @@ class LCMXO2Primer:
|
|||||||
|
|
||||||
DEV_ID_LCMXO2_7000HC = b'\x01\x2B\xD0\x43'
|
DEV_ID_LCMXO2_7000HC = b'\x01\x2B\xD0\x43'
|
||||||
|
|
||||||
def __init__(self, write: Callable[[bytes], None], read: Callable[[int], bytes], progress: Callable[[int, int, str], None]):
|
def __init__(
|
||||||
|
self,
|
||||||
|
write: Callable[[bytes], None],
|
||||||
|
read: Callable[[int], bytes],
|
||||||
|
flush: Callable[[None], None],
|
||||||
|
progress: Callable[[int, int, str], None]
|
||||||
|
):
|
||||||
self.__write = write
|
self.__write = write
|
||||||
self.__read = read
|
self.__read = read
|
||||||
|
self.__flush = flush
|
||||||
self.__progress = progress
|
self.__progress = progress
|
||||||
|
|
||||||
def __cmd_execute(self, cmd: bytes, data: bytes=b'') -> bytes:
|
def __cmd_execute(self, cmd: bytes, data: bytes=b'') -> bytes:
|
||||||
@ -355,14 +380,20 @@ class LCMXO2Primer:
|
|||||||
packet += data
|
packet += data
|
||||||
packet += crc32(packet).to_bytes(4, byteorder='little')
|
packet += crc32(packet).to_bytes(4, byteorder='little')
|
||||||
self.__write(packet)
|
self.__write(packet)
|
||||||
|
self.__flush()
|
||||||
|
|
||||||
response = self.__read(5)
|
response = self.__read(5)
|
||||||
if (len(response) != 5):
|
if (len(response) != 5):
|
||||||
raise LCMXO2PrimerException(f'No response received [{cmd}]')
|
raise LCMXO2PrimerException(f'No response received [{cmd}]')
|
||||||
length = int.from_bytes(response[4:5], byteorder='little')
|
length = int.from_bytes(response[4:5], byteorder='little')
|
||||||
response += self.__read(length)
|
response_data = self.__read(length)
|
||||||
calculated_checksum = crc32(response)
|
if (len(response_data) != length):
|
||||||
received_checksum = int.from_bytes(self.__read(4), byteorder='little')
|
raise LCMXO2PrimerException(f'No response data received [{cmd}]')
|
||||||
|
checksum = self.__read(4)
|
||||||
|
if (len(checksum) != 4):
|
||||||
|
raise LCMXO2PrimerException(f'No response data checksum received [{cmd}]')
|
||||||
|
calculated_checksum = crc32(response + response_data)
|
||||||
|
received_checksum = int.from_bytes(checksum, byteorder='little')
|
||||||
|
|
||||||
if (response[0:3] != b'RSP'):
|
if (response[0:3] != b'RSP'):
|
||||||
raise LCMXO2PrimerException(f'Invalid response token [{response[0:3]} / {cmd}]')
|
raise LCMXO2PrimerException(f'Invalid response token [{response[0:3]} / {cmd}]')
|
||||||
@ -371,16 +402,19 @@ class LCMXO2Primer:
|
|||||||
if (calculated_checksum != received_checksum):
|
if (calculated_checksum != received_checksum):
|
||||||
raise LCMXO2PrimerException(f'Invalid response checksum [{cmd}]')
|
raise LCMXO2PrimerException(f'Invalid response checksum [{cmd}]')
|
||||||
|
|
||||||
return response[5:]
|
return response_data
|
||||||
|
|
||||||
def connect(self, id: bytes) -> None:
|
def connect(self, id: bytes) -> None:
|
||||||
primer_id = self.__cmd_execute(self.__CMD_GET_PRIMER_ID)
|
try:
|
||||||
if (primer_id != self.__PRIMER_ID_LCMXO2):
|
primer_id = self.__cmd_execute(self.__CMD_GET_PRIMER_ID)
|
||||||
raise LCMXO2PrimerException('Invalid primer ID received')
|
if (primer_id != self.__PRIMER_ID_LCMXO2):
|
||||||
|
raise LCMXO2PrimerException('Invalid primer ID received')
|
||||||
|
|
||||||
dev_id = self.__cmd_execute(self.__CMD_GET_DEVICE_ID)
|
dev_id = self.__cmd_execute(self.__CMD_GET_DEVICE_ID)
|
||||||
if (dev_id != id):
|
if (dev_id != id):
|
||||||
raise LCMXO2PrimerException('Invalid FPGA device id received')
|
raise LCMXO2PrimerException('Invalid FPGA device id received')
|
||||||
|
except LCMXO2PrimerException as e:
|
||||||
|
raise LCMXO2PrimerException(f'Could not connect to the LCMXO2 primer ({e})')
|
||||||
|
|
||||||
def load_flash_and_run(self, data: bytes, description: str) -> None:
|
def load_flash_and_run(self, data: bytes, description: str) -> None:
|
||||||
erase_description = f'{description} / Erase'
|
erase_description = f'{description} / Erase'
|
||||||
@ -599,8 +633,8 @@ class SC64BringUp:
|
|||||||
write_timeout=self.__SERIAL_TIMEOUT
|
write_timeout=self.__SERIAL_TIMEOUT
|
||||||
)
|
)
|
||||||
|
|
||||||
stm32_bootloader = STM32Bootloader(link.write, link.read, self.__progress)
|
stm32_bootloader = STM32Bootloader(link.write, link.read, link.flush, self.__progress)
|
||||||
lcmxo2_primer = LCMXO2Primer(link.write, link.read, self.__progress)
|
lcmxo2_primer = LCMXO2Primer(link.write, link.read, link.flush, self.__progress)
|
||||||
|
|
||||||
stm32_bootloader.connect(stm32_bootloader.DEV_ID_STM32G030XX)
|
stm32_bootloader.connect(stm32_bootloader.DEV_ID_STM32G030XX)
|
||||||
stm32_bootloader.load_ram_and_run(self.__sc64_update_data.get_primer_data(), 'FPGA primer -> STM32 RAM')
|
stm32_bootloader.load_ram_and_run(self.__sc64_update_data.get_primer_data(), 'FPGA primer -> STM32 RAM')
|
||||||
@ -645,7 +679,7 @@ if __name__ == '__main__':
|
|||||||
sc64_bring_up = SC64BringUp(progress=utils.progress)
|
sc64_bring_up = SC64BringUp(progress=utils.progress)
|
||||||
|
|
||||||
Utils.log()
|
Utils.log()
|
||||||
Utils.info('[ Welcome to SC64 flashcart board bring-up! ]')
|
Utils.info('[ Welcome to the SummerCart64 flashcart board bring-up! ]')
|
||||||
Utils.log()
|
Utils.log()
|
||||||
|
|
||||||
Utils.log(f'Serial port: {port}')
|
Utils.log(f'Serial port: {port}')
|
||||||
@ -683,6 +717,7 @@ if __name__ == '__main__':
|
|||||||
original_sigint_handler = signal.getsignal(signal.SIGINT)
|
original_sigint_handler = signal.getsignal(signal.SIGINT)
|
||||||
try:
|
try:
|
||||||
signal.signal(signal.SIGINT, lambda *kwargs: utils.exit_warning())
|
signal.signal(signal.SIGINT, lambda *kwargs: utils.exit_warning())
|
||||||
|
Utils.log('Starting SC64 flashcart board bring-up...')
|
||||||
sc64_bring_up.start_bring_up(port, bootloader_only)
|
sc64_bring_up.start_bring_up(port, bootloader_only)
|
||||||
except (serial.SerialException, STM32BootloaderException, LCMXO2PrimerException, SC64Exception) as e:
|
except (serial.SerialException, STM32BootloaderException, LCMXO2PrimerException, SC64Exception) as e:
|
||||||
if (utils.get_progress_active):
|
if (utils.get_progress_active):
|
||||||
|
Loading…
Reference in New Issue
Block a user