mirror of
https://github.com/Polprzewodnikowy/SummerCart64.git
synced 2024-11-24 22:56:52 +01:00
added voltage and temperature diagnostic
This commit is contained in:
parent
e1ecb0cac3
commit
5c4ad29f61
@ -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 |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
@ -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 {
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#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 "led.h"
|
||||||
#include "rtc.h"
|
#include "rtc.h"
|
||||||
@ -84,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),
|
||||||
@ -226,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);
|
||||||
@ -700,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;
|
||||||
|
@ -45,23 +45,23 @@ static void hw_clock_init (void) {
|
|||||||
|
|
||||||
static void hw_timeout_init (void) {
|
static void hw_timeout_init (void) {
|
||||||
RCC->APBENR1 |= RCC_APBENR1_DBGEN;
|
RCC->APBENR1 |= RCC_APBENR1_DBGEN;
|
||||||
DBG->APBFZ2 |= DBG_APB_FZ2_DBG_TIM17_STOP;
|
DBG->APBFZ2 |= DBG_APB_FZ2_DBG_TIM1_STOP;
|
||||||
|
|
||||||
RCC->APBENR2 |= RCC_APBENR2_TIM17EN;
|
RCC->APBENR2 |= RCC_APBENR2_TIM1EN;
|
||||||
|
|
||||||
TIM17->CR1 = TIM_CR1_OPM;
|
TIM1->CR1 = TIM_CR1_OPM;
|
||||||
TIM17->PSC = (((CPU_FREQ / 1000 / 1000) * TIMEOUT_US_PER_TICK) - 1);
|
TIM1->PSC = (((CPU_FREQ / 1000 / 1000) * TIMEOUT_US_PER_TICK) - 1);
|
||||||
TIM17->EGR = TIM_EGR_UG;
|
TIM1->EGR = TIM_EGR_UG;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void hw_timeout_start (void) {
|
static void hw_timeout_start (void) {
|
||||||
TIM17->CR1 &= ~(TIM_CR1_CEN);
|
TIM1->CR1 &= ~(TIM_CR1_CEN);
|
||||||
TIM17->CNT = 0;
|
TIM1->CNT = 0;
|
||||||
TIM17->CR1 |= TIM_CR1_CEN;
|
TIM1->CR1 |= TIM_CR1_CEN;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool hw_timeout_occured (uint32_t timeout_us) {
|
static bool hw_timeout_occured (uint32_t timeout_us) {
|
||||||
uint16_t count = TIM17->CNT;
|
uint16_t count = TIM1->CNT;
|
||||||
|
|
||||||
uint32_t adjusted_timeout = ((timeout_us + (TIMEOUT_US_PER_TICK - 1)) / TIMEOUT_US_PER_TICK);
|
uint32_t adjusted_timeout = ((timeout_us + (TIMEOUT_US_PER_TICK - 1)) / TIMEOUT_US_PER_TICK);
|
||||||
|
|
||||||
@ -73,29 +73,46 @@ static bool hw_timeout_occured (uint32_t timeout_us) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#define DELAY_US_PER_TICK (1)
|
||||||
#define DELAY_MS_PER_TICK (1)
|
#define DELAY_MS_PER_TICK (1)
|
||||||
|
|
||||||
static void hw_delay_init (void) {
|
static void hw_delay_init (void) {
|
||||||
RCC->APBENR1 |= RCC_APBENR1_DBGEN;
|
RCC->APBENR1 |= RCC_APBENR1_DBGEN;
|
||||||
DBG->APBFZ2 |= DBG_APB_FZ2_DBG_TIM16_STOP;
|
DBG->APBFZ1 |= DBG_APB_FZ1_DBG_TIM3_STOP;
|
||||||
|
|
||||||
RCC->APBENR2 |= RCC_APBENR2_TIM16EN;
|
RCC->APBENR1 |= RCC_APBENR1_TIM3EN;
|
||||||
|
|
||||||
TIM16->CR1 = TIM_CR1_OPM;
|
TIM3->CR1 = TIM_CR1_OPM;
|
||||||
TIM16->PSC = (((CPU_FREQ / 1000) * DELAY_MS_PER_TICK) - 1);
|
TIM3->EGR = TIM_EGR_UG;
|
||||||
TIM16->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) {
|
void hw_delay_ms (uint32_t delay_ms) {
|
||||||
TIM16->CR1 &= ~(TIM_CR1_CEN);
|
TIM3->CR1 &= ~(TIM_CR1_CEN);
|
||||||
TIM16->CNT = 0;
|
TIM3->PSC = (((CPU_FREQ / 1000) * DELAY_MS_PER_TICK) - 1);
|
||||||
TIM16->CR1 |= TIM_CR1_CEN;
|
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);
|
uint32_t adjusted_delay = ((delay_ms + (DELAY_MS_PER_TICK - 1)) / DELAY_MS_PER_TICK);
|
||||||
|
|
||||||
uint16_t count;
|
uint16_t count;
|
||||||
do {
|
do {
|
||||||
count = TIM16->CNT;
|
count = TIM3->CNT;
|
||||||
} while ((count < adjusted_delay) && (count != 0xFFFF));
|
} while ((count < adjusted_delay) && (count != 0xFFFF));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -493,6 +510,61 @@ void hw_loader_get_parameters (loader_parameters_t *parameters) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#define ADC_VREF_CAL_POINT (3000)
|
||||||
|
#define ADC_VREF_CAL_VALUE (*(uint16_t *) (0x1FFF75AAUL))
|
||||||
|
|
||||||
|
#define TEMP_CAL_POINT_1 (30)
|
||||||
|
#define TEMP_CAL_VALUE_1 (*(uint16_t *) (0x1FFF75A8UL))
|
||||||
|
|
||||||
|
#define TEMP_CAL_POINT_2 (130)
|
||||||
|
#define TEMP_CAL_VALUE_2 (*(uint16_t *) (0x1FFF75CAUL))
|
||||||
|
|
||||||
|
#define TEMP_CAL_VREF (3000)
|
||||||
|
|
||||||
|
#define TEMP_SCALE (10)
|
||||||
|
|
||||||
|
static void hw_adc_init (void) {
|
||||||
|
RCC->APBENR2 |= RCC_APBENR2_ADCEN;
|
||||||
|
|
||||||
|
ADC1->CFGR2 = ADC_CFGR2_CKMODE_1;
|
||||||
|
|
||||||
|
ADC->CCR = (ADC_CCR_TSEN | ADC_CCR_VREFEN);
|
||||||
|
ADC1->CR = ADC_CR_ADVREGEN;
|
||||||
|
|
||||||
|
hw_delay_us(120);
|
||||||
|
|
||||||
|
ADC1->ISR = ADC_ISR_EOCAL;
|
||||||
|
ADC1->CR |= ADC_CR_ADCAL;
|
||||||
|
while (!(ADC1->ISR & ADC_ISR_EOCAL));
|
||||||
|
|
||||||
|
ADC1->CFGR1 = (ADC_CFGR1_AUTOFF | ADC_CFGR1_WAIT | ADC_CFGR1_SCANDIR);
|
||||||
|
ADC1->CFGR2 |= (ADC_CFGR2_OVSS_2 | ADC_CFGR2_OVSR_1 | ADC_CFGR2_OVSR_0 | ADC_CFGR2_OVSE);
|
||||||
|
ADC1->SMPR = (ADC_SMPR_SMP1_2 | ADC_SMPR_SMP1_1 | ADC_SMPR_SMP1_0);
|
||||||
|
|
||||||
|
ADC1->ISR = ADC_ISR_CCRDY;
|
||||||
|
ADC1->CHSELR = (ADC_CHSELR_CHSEL13 | ADC_CHSELR_CHSEL12);
|
||||||
|
while (!(ADC1->ISR & ADC_ISR_CCRDY));
|
||||||
|
|
||||||
|
ADC1->CR |= ADC_CR_ADEN;
|
||||||
|
}
|
||||||
|
|
||||||
|
void hw_adc_read_voltage_temperature (uint16_t *voltage, int16_t *temperature) {
|
||||||
|
ADC1->CR |= ADC_CR_ADSTART;
|
||||||
|
|
||||||
|
while (!(ADC1->ISR & ADC_ISR_EOC));
|
||||||
|
uint16_t adc_vref = ((ADC_VREF_CAL_POINT * ADC_VREF_CAL_VALUE) / ADC1->DR);
|
||||||
|
|
||||||
|
while (!(ADC1->ISR & ADC_ISR_EOC));
|
||||||
|
int16_t adc_temp = ((ADC1->DR * adc_vref) / TEMP_CAL_VREF);
|
||||||
|
|
||||||
|
*voltage = adc_vref;
|
||||||
|
*temperature = (
|
||||||
|
((adc_temp - TEMP_CAL_VALUE_1) * (TEMP_CAL_POINT_2 - TEMP_CAL_POINT_1) * TEMP_SCALE) /
|
||||||
|
(TEMP_CAL_VALUE_2 - TEMP_CAL_VALUE_1)
|
||||||
|
) + (TEMP_CAL_POINT_1 * TEMP_SCALE);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void hw_led_init (void) {
|
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);
|
||||||
}
|
}
|
||||||
@ -530,6 +602,7 @@ void hw_app_init (void) {
|
|||||||
hw_clock_init();
|
hw_clock_init();
|
||||||
hw_timeout_init();
|
hw_timeout_init();
|
||||||
hw_delay_init();
|
hw_delay_init();
|
||||||
|
hw_adc_init();
|
||||||
hw_led_init();
|
hw_led_init();
|
||||||
hw_misc_init();
|
hw_misc_init();
|
||||||
hw_uart_init();
|
hw_uart_init();
|
||||||
|
@ -85,6 +85,8 @@ 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_adc_read_voltage_temperature (uint16_t *voltage, int16_t *temperature);
|
||||||
|
|
||||||
void hw_primer_init (void);
|
void hw_primer_init (void);
|
||||||
void hw_loader_init (void);
|
void hw_loader_init (void);
|
||||||
void hw_app_init (void);
|
void hw_app_init (void);
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
#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"
|
||||||
@ -21,6 +22,9 @@
|
|||||||
|
|
||||||
#define DEBUG_WRITE_TIMEOUT_MS (1000)
|
#define DEBUG_WRITE_TIMEOUT_MS (1000)
|
||||||
|
|
||||||
|
#define DIAGNOSTIC_DATA_MARKER (1 << 31)
|
||||||
|
#define DIAGNOSTIC_DATA_VERSION (1)
|
||||||
|
|
||||||
|
|
||||||
enum rx_state {
|
enum rx_state {
|
||||||
RX_STATE_IDLE,
|
RX_STATE_IDLE,
|
||||||
@ -381,15 +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;
|
||||||
p.response_info.data[0] = 0;
|
p.response_info.data[0] = (DIAGNOSTIC_DATA_MARKER | DIAGNOSTIC_DATA_VERSION);
|
||||||
p.response_info.data[1] = 0;
|
p.response_info.data[1] = (uint32_t) (voltage);
|
||||||
p.response_info.data[2] = 0;
|
p.response_info.data[2] = (uint32_t) (temperature);
|
||||||
p.response_info.data[3] = 0;
|
p.response_info.data[3] = 0;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
p.rx_state = RX_STATE_IDLE;
|
p.rx_state = RX_STATE_IDLE;
|
||||||
|
@ -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(())
|
||||||
}
|
}
|
||||||
|
@ -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()?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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)
|
||||||
|
Loading…
Reference in New Issue
Block a user