pull basics from mk4
This commit is contained in:
parent
21e84b84ef
commit
2f2a56bd12
1
stm32/COLDCARD_Q1/c-modules
Symbolic link
1
stm32/COLDCARD_Q1/c-modules
Symbolic link
@ -0,0 +1 @@
|
||||
../../external/c-modules
|
||||
46
stm32/COLDCARD_Q1/ckcc-port.h
Normal file
46
stm32/COLDCARD_Q1/ckcc-port.h
Normal file
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* (c) Copyright 2021 by Coinkite Inc. This file is covered by license found in COPYING-CC.
|
||||
*
|
||||
* based on ports/stm32/mpconfigport.h but overrides only
|
||||
*
|
||||
*/
|
||||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2013-2017 Damien P. George
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
// Options to control how MicroPython is built for this port,
|
||||
// overriding defaults in py/mpconfig.h.
|
||||
|
||||
// board specific definitions
|
||||
#include "mpconfigboard.h"
|
||||
#include "mpconfigboard_common.h"
|
||||
|
||||
// default port config: see ports/stm32
|
||||
#include "mpconfigport.h"
|
||||
|
||||
#undef MICROPY_PY_MACHINE_PULSE
|
||||
#define MICROPY_PY_MACHINE_PULSE (0)
|
||||
|
||||
|
||||
81
stm32/COLDCARD_Q1/clocks.c
Normal file
81
stm32/COLDCARD_Q1/clocks.c
Normal file
@ -0,0 +1,81 @@
|
||||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2013, 2014 Damien P. George
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "py/mphal.h"
|
||||
#include "irq.h"
|
||||
|
||||
void __fatal_error(const char *msg);
|
||||
|
||||
void SystemInit(void)
|
||||
{
|
||||
// replace code from
|
||||
// l-mpy/lib/stm32lib/CMSIS/STM32L4xx/Source/Templates/system_stm32l4xx.c
|
||||
|
||||
// FPU settings
|
||||
#if (__FPU_PRESENT == 1) && (__FPU_USED == 1)
|
||||
SCB->CPACR |= ((3UL << 10*2)|(3UL << 11*2)); /* set CP10 and CP11 Full Access */
|
||||
#endif
|
||||
|
||||
// Leave clock details unchanged! Do not reset RCC.
|
||||
|
||||
// Disable all interrupts
|
||||
RCC->CIER = 0x00000000;
|
||||
|
||||
// Configure the Vector Table location add offset address
|
||||
#ifdef VECT_TAB_SRAM
|
||||
SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM */
|
||||
#else
|
||||
SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH */
|
||||
#endif
|
||||
|
||||
// This global controls the return value of HAL_RCC_GetHCLKFreq()
|
||||
// see clocks.h of bootrom ... SYSCLK in Hz = 120Mhz
|
||||
SystemCoreClock = 120000000;
|
||||
}
|
||||
|
||||
void SystemClock_Config(void)
|
||||
{
|
||||
// See code in clocks.c of bootloader for actual clock setup.
|
||||
|
||||
#if 0
|
||||
__PWR_CLK_ENABLE();
|
||||
HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1);
|
||||
#endif
|
||||
|
||||
// redundant/override HAL_InitTick called from stm32_main just before this
|
||||
HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/(1000*8));
|
||||
HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK_DIV8);
|
||||
|
||||
NVIC_SetPriority(SysTick_IRQn, NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, TICK_INT_PRIORITY, 0));
|
||||
|
||||
// bugfix? why is this needed?
|
||||
enable_irq(IRQ_STATE_ENABLED);
|
||||
}
|
||||
|
||||
// EOF
|
||||
13
stm32/COLDCARD_Q1/initfs.c
Normal file
13
stm32/COLDCARD_Q1/initfs.c
Normal file
@ -0,0 +1,13 @@
|
||||
/*
|
||||
* (c) Copyright 2021 by Coinkite Inc. This file is covered by license found in COPYING-CC.
|
||||
*
|
||||
*/
|
||||
|
||||
int factory_reset_create_filesystem(void)
|
||||
{
|
||||
// Replaces standard version of this function, so it's useful for this project.
|
||||
// - but do not create a filesystem, instead do it in python
|
||||
return 0; // success
|
||||
}
|
||||
|
||||
// EOF
|
||||
47
stm32/COLDCARD_Q1/layout.ld
Normal file
47
stm32/COLDCARD_Q1/layout.ld
Normal file
@ -0,0 +1,47 @@
|
||||
/*
|
||||
GNU linker script for Coldcard Mk4 running on STM32L4s5 with 2MB of flash
|
||||
*/
|
||||
|
||||
/* Specify the memory areas */
|
||||
MEMORY
|
||||
{
|
||||
FLASH (rx) : ORIGIN = 0x08020000, LENGTH = 1984K
|
||||
|
||||
/* Flash layout:
|
||||
- first 64k of flash is the Coldcard Mk4 bootloader
|
||||
- next 16k of flash reserved for interupt vectors and few other little things
|
||||
- (bulk of firmware ~ 1.5meg)
|
||||
- 512k of user settings in LFS2 filesystem
|
||||
*/
|
||||
FLASH_ISR (rx) : ORIGIN = 0x08020000, LENGTH = 16K
|
||||
FLASH_TEXT (rx) : ORIGIN = 0x08024000, LENGTH = 1392K
|
||||
FLASH_FS (r) : ORIGIN = 0x08180000, LENGTH = 512K
|
||||
|
||||
/* SRAM1,2, and 3 are continuous, highest 0x2000 reserved for bootloader */
|
||||
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 0x9e000
|
||||
}
|
||||
|
||||
ENTRY(Reset_Handler)
|
||||
|
||||
/* produce a link error if there is not this amount of RAM for these sections */
|
||||
_minimum_stack_size = 2K;
|
||||
_minimum_heap_size = 16K;
|
||||
|
||||
/* Define the stack. The stack is full descending so begins just above last byte of RAM,
|
||||
or bottom of FS cache.. Note that EABI requires the stack to be 8-byte aligned for a call. */
|
||||
|
||||
/* RAM extents for the garbage collector */
|
||||
_ram_start = ORIGIN(RAM);
|
||||
_ram_end = ORIGIN(RAM) + LENGTH(RAM);
|
||||
|
||||
_ram_fs_cache_end = _ram_end;
|
||||
_ram_fs_cache_start = _ram_fs_cache_end - 8K; /* fs cache = 8K .. one flash sector */
|
||||
|
||||
_estack = _ram_fs_cache_start - _estack_reserve;
|
||||
_sstack = _estack - 16K; /* stack = 16K */
|
||||
|
||||
_heap_start = _ebss; /* heap starts just after statically allocated memory */
|
||||
_heap_end = _sstack; /* bss + heap, tunable by adjusting stack size */
|
||||
|
||||
_flash_fs_start = ORIGIN(FLASH_FS);
|
||||
_flash_fs_end = ORIGIN(FLASH_FS) + LENGTH(FLASH_FS);
|
||||
359
stm32/COLDCARD_Q1/modckcc.c
Normal file
359
stm32/COLDCARD_Q1/modckcc.c
Normal file
@ -0,0 +1,359 @@
|
||||
//
|
||||
// (c) Copyright 2018 by Coinkite Inc. This file is covered by license found in COPYING-CC.
|
||||
//
|
||||
// modckcc.c - module for Coldcard hardware features and glue.
|
||||
//
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "modckcc.h"
|
||||
#include "rng.h"
|
||||
#include "usb.h"
|
||||
#include "flash.h"
|
||||
#include "bufhelper.h"
|
||||
#include "py/gc.h"
|
||||
#include "py/runtime.h"
|
||||
#include "py/mphal.h"
|
||||
#include "py/mpstate.h"
|
||||
#include "py/stackctrl.h"
|
||||
#include "boardctrl.h"
|
||||
#include "softtimer.h"
|
||||
#include "ulight.h"
|
||||
#include "uart.h"
|
||||
|
||||
#include "storage.h"
|
||||
#include "usb.h"
|
||||
#include "extint.h"
|
||||
#include "lib/utils/interrupt_char.h" // for mp_interrupt_char
|
||||
|
||||
// this file needs -O0 for it to work well.
|
||||
#pragma GCC push_options
|
||||
#pragma GCC optimize ("O0")
|
||||
|
||||
// Presume genuine light is on, at start
|
||||
STATIC bool presumably_green_light = true;
|
||||
|
||||
MP_DECLARE_CONST_FUN_OBJ_0(pyb_rng_get_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_1(pyb_rng_get_bytes_obj);
|
||||
|
||||
// See startup.S where this table of entry points/version numbers is defined
|
||||
typedef struct {
|
||||
uint32_t callgate_entry;
|
||||
uint32_t version_number;
|
||||
uint32_t reserved[4];
|
||||
} bootloaderInfoTable_t;
|
||||
|
||||
#define BOOTLOADER_TABLE (*((bootloaderInfoTable_t *)0x08000040))
|
||||
|
||||
STATIC int callgate_lower(uint32_t method_num, uint32_t arg2, mp_buffer_info_t *io_buf)
|
||||
{
|
||||
uint32_t dest = BOOTLOADER_TABLE.callgate_entry;
|
||||
|
||||
// +4 because that's required by call gate for firewall
|
||||
// +1 to set LSB because we know a BLX instruction will be used to
|
||||
// get there and we know its thumb code
|
||||
// - also 0x100 aligned.
|
||||
assert((dest & 0xff) == 0x05);
|
||||
|
||||
ulight_off();
|
||||
mp_uint_t before = disable_irq();
|
||||
|
||||
// XXX this doesn't work with compiler optimizations enabled (ie. -O0 only!!)
|
||||
|
||||
// Call the gate; it will trash the normal function-call registers (r0-4)
|
||||
// but also r9 and r10. Does not use our stack.
|
||||
//
|
||||
// references:
|
||||
// - <http://www.ethernut.de/en/documents/arm-inline-asm.html>
|
||||
// - <https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html>
|
||||
//
|
||||
int rv = -2;
|
||||
register int r_method asm("r0") = method_num;
|
||||
register const char *tx asm("r1") = io_buf ? io_buf->buf : NULL;
|
||||
register uint32_t tx_len asm("r2") = io_buf ? io_buf->len: 0;
|
||||
register uint32_t r_arg2 asm("r3") = arg2;
|
||||
|
||||
asm volatile( "blx %[dest] \n"
|
||||
"str r0, %[rv]"
|
||||
: [rv] "=m" (rv)
|
||||
: [dest] "r" (dest), "r" (tx), "r" (tx_len), "r" (r_arg2), "r" (r_method)
|
||||
: "r9", "r10"
|
||||
);
|
||||
|
||||
enable_irq(before);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
STATIC mp_obj_t sec_oneway_gate(mp_obj_t method_obj, mp_obj_t arg2_obj)
|
||||
{
|
||||
// jump to the callgate, but don't expect to come back. Good for DFU entry.
|
||||
|
||||
uint32_t dest = BOOTLOADER_TABLE.callgate_entry;
|
||||
|
||||
uint32_t num = mp_obj_get_int(method_obj);
|
||||
uint32_t arg2 = mp_obj_get_int(arg2_obj);
|
||||
|
||||
pyb_usb_dev_deinit();
|
||||
storage_flush();
|
||||
ulight_off();
|
||||
|
||||
// NOTE: this may not work with compiler optimizations enabled (ie. -O0 only!!)
|
||||
|
||||
mp_uint_t before = disable_irq();
|
||||
|
||||
int rv = -2; // not really used.
|
||||
register int method_num asm("r0") = num;
|
||||
register const char *tx asm("r1") = 0;
|
||||
register uint32_t tx_len asm("r2") = 0;
|
||||
register uint32_t r_arg2 asm("r3") = arg2;
|
||||
|
||||
asm volatile( "blx %[dest] \n"
|
||||
"str r0, %[rv]"
|
||||
: [rv] "=m" (rv)
|
||||
: [dest] "r" (dest), "r" (tx), "r" (tx_len), "r" (r_arg2), "r" (method_num)
|
||||
: "r9", "r10"
|
||||
);
|
||||
|
||||
enable_irq(before);
|
||||
|
||||
// not reached, except maybe error cases
|
||||
return mp_obj_new_int(rv);
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_2(sec_oneway_gate_obj, sec_oneway_gate);
|
||||
|
||||
STATIC mp_obj_t sec_gate(mp_obj_t method_obj, mp_obj_t send_arg, mp_obj_t arg2_obj)
|
||||
{
|
||||
|
||||
// first and last args are simple integers
|
||||
uint32_t method_num = mp_obj_get_int(method_obj);
|
||||
uint32_t arg2 = mp_obj_get_int(arg2_obj);
|
||||
|
||||
// 2nd arg: buffer to send to function, or None for NULL
|
||||
mp_buffer_info_t send_buf;
|
||||
bool is_none = false;
|
||||
|
||||
if(send_arg != mp_const_none) {
|
||||
mp_get_buffer_raise(send_arg, &send_buf, MP_BUFFER_RW);
|
||||
} else {
|
||||
is_none = true;
|
||||
}
|
||||
|
||||
int rv = callgate_lower(method_num, arg2, is_none ? NULL : &send_buf);
|
||||
|
||||
#if 0
|
||||
// bugfix: if bootloader (V1.0.1) calls systick_setup(), this will correct register
|
||||
SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk |
|
||||
SysTick_CTRL_TICKINT_Msk |
|
||||
SysTick_CTRL_ENABLE_Msk;
|
||||
#endif
|
||||
|
||||
|
||||
return mp_obj_new_int(rv);
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_3(sec_gate_obj, sec_gate);
|
||||
|
||||
|
||||
// Since we cache state of green light, need a way for us
|
||||
// to be reset, altho has no bearing on real operation of 508a.
|
||||
STATIC mp_obj_t presume_green(void)
|
||||
{
|
||||
presumably_green_light = true;
|
||||
|
||||
return mp_const_none;
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_0(presume_green_obj, presume_green);
|
||||
|
||||
|
||||
STATIC mp_obj_t is_simulator(void)
|
||||
{
|
||||
return MP_OBJ_NEW_SMALL_INT(0);
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_0(is_simulator_obj, is_simulator);
|
||||
|
||||
STATIC mp_obj_t is_debug_build(void)
|
||||
{
|
||||
return MP_OBJ_NEW_SMALL_INT(COLDCARD_DEBUG);
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_0(is_debug_build_obj, is_debug_build);
|
||||
|
||||
STATIC mp_obj_t get_cpu_id(void)
|
||||
{
|
||||
// Are we running on a STM32L496RG6? If so, expect 0x461
|
||||
return MP_OBJ_NEW_SMALL_INT(DBGMCU->IDCODE & 0xfff);
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_0(get_cpu_id_obj, get_cpu_id);
|
||||
|
||||
|
||||
STATIC mp_obj_t vcp_enabled(mp_obj_t new_val)
|
||||
{
|
||||
// see vcp_lockdown.c where this is used
|
||||
extern bool ckcc_vcp_enabled;
|
||||
|
||||
// Report/Control the VCP lockout. Call with None to readback.
|
||||
if(mp_obj_is_integer(new_val)) {
|
||||
ckcc_vcp_enabled = !!(mp_obj_get_int_truncated(new_val));
|
||||
|
||||
mp_interrupt_char = ckcc_vcp_enabled ? 3 : -1;
|
||||
}
|
||||
|
||||
return MP_OBJ_NEW_SMALL_INT(ckcc_vcp_enabled);
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(vcp_enabled_obj, vcp_enabled);
|
||||
|
||||
|
||||
STATIC mp_obj_t stack_limit(mp_obj_t new_val)
|
||||
{
|
||||
// Report or change the stack limit, in bytes. Probably less than 0x4000.
|
||||
if(mp_obj_is_integer(new_val)) {
|
||||
mp_int_t limit = mp_obj_get_int_truncated(new_val);
|
||||
|
||||
// Small values will cause immediate crash due to stack-depth checking, so avoid.
|
||||
if((limit < 1024) || (limit > 64*1024)) {
|
||||
mp_raise_ValueError(NULL);
|
||||
}
|
||||
|
||||
mp_stack_set_limit(limit);
|
||||
}
|
||||
|
||||
return MP_OBJ_NEW_SMALL_INT(MP_STATE_THREAD(stack_limit));
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(stack_limit_obj, stack_limit);
|
||||
|
||||
STATIC mp_obj_t usb_active(void)
|
||||
{
|
||||
// something happened at the class-driver level of USB.
|
||||
// - keep the light flashing
|
||||
ckcc_usb_active = true;
|
||||
|
||||
return mp_const_none;
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_0(usb_active_obj, usb_active);
|
||||
|
||||
STATIC mp_obj_t breakpoint(void)
|
||||
{
|
||||
// drop into the debugger, if connected.
|
||||
asm("BKPT #0");
|
||||
|
||||
return mp_const_none;
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_0(breakpoint_obj, breakpoint);
|
||||
|
||||
STATIC mp_obj_t watchpoint(volatile mp_obj_t arg1)
|
||||
{
|
||||
// just be an empty function that we can set as a breakpoint
|
||||
// in the debugger... also gives some visiblilty into a single object
|
||||
|
||||
return mp_const_none;
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(watchpoint_obj, watchpoint);
|
||||
|
||||
// See psram.c
|
||||
extern const mp_obj_type_t psram_type;
|
||||
|
||||
STATIC const mp_rom_map_elem_t ckcc_module_globals_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_ckcc) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_rng), MP_ROM_PTR(&pyb_rng_get_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_rng_bytes), MP_ROM_PTR(&pyb_rng_get_bytes_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_gate), MP_ROM_PTR(&sec_gate_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_oneway), MP_ROM_PTR(&sec_oneway_gate_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_is_simulator), MP_ROM_PTR(&is_simulator_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_is_debug_build), MP_ROM_PTR(&is_debug_build_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_get_cpu_id), MP_ROM_PTR(&get_cpu_id_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_vcp_enabled), MP_ROM_PTR(&vcp_enabled_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_presume_green), MP_ROM_PTR(&presume_green_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_breakpoint), MP_ROM_PTR(&breakpoint_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_watchpoint), MP_ROM_PTR(&watchpoint_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_stack_limit), MP_ROM_PTR(&stack_limit_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_usb_active), MP_ROM_PTR(&usb_active_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_PSRAM), MP_ROM_PTR(&psram_type) },
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(ckcc_module_globals, ckcc_module_globals_table);
|
||||
|
||||
const mp_obj_module_t ckcc_module = {
|
||||
.base = { &mp_type_module },
|
||||
.globals = (mp_obj_dict_t*)&ckcc_module_globals,
|
||||
};
|
||||
|
||||
MP_REGISTER_MODULE(MP_QSTR_ckcc, ckcc_module, 1);
|
||||
|
||||
void ckcc_early_init(void)
|
||||
{
|
||||
// Add system-wide init code here.
|
||||
|
||||
// Disable ^C to interrupt code... but see mp_hal_set_interrupt_char()
|
||||
// for best disable code.
|
||||
mp_interrupt_char = -1;
|
||||
|
||||
// Do the equivilent of "py.usb_mode(None)" in boot.py
|
||||
extern mp_uint_t pyb_usb_flags;
|
||||
pyb_usb_flags |= PYB_USB_FLAG_USB_MODE_CALLED;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ckcc_boardctrl_before_boot_py(boardctrl_state_t *state)
|
||||
{
|
||||
// do not run /boot.py even if it exists
|
||||
state->run_boot_py = false;
|
||||
|
||||
// Clear PSRAM from previous cycles
|
||||
extern void psram_init(void);
|
||||
psram_init();
|
||||
|
||||
// setup USB activity light
|
||||
ulight_setup();
|
||||
}
|
||||
void ckcc_boardctrl_after_boot_py(boardctrl_state_t *state)
|
||||
{
|
||||
// nothing to do, no way to report failures anyway
|
||||
}
|
||||
|
||||
// ckcc_heap_start()
|
||||
//
|
||||
void *
|
||||
ckcc_heap_start(void)
|
||||
{
|
||||
// see layout.ld (linker script)
|
||||
extern uint32_t _heap_start;
|
||||
|
||||
return &_heap_start;
|
||||
}
|
||||
|
||||
// ckcc_heap_start()
|
||||
//
|
||||
void *
|
||||
ckcc_heap_end(void)
|
||||
{
|
||||
extern uint32_t _ram_end;
|
||||
uint8_t *rv = (uint8_t *)&_ram_end;
|
||||
|
||||
if((DBGMCU->IDCODE & 0xfff) == 0x461) {
|
||||
rv += 160*1024;
|
||||
}
|
||||
|
||||
// Mark 1 and 2
|
||||
return rv;
|
||||
}
|
||||
|
||||
// There is no classical C heap in bare-metal ports, only Python
|
||||
// garbage-collected heap. For completeness, emulate C heap via
|
||||
// GC heap. Note that MicroPython core never uses malloc() and friends,
|
||||
// but I need these for the C-language extensions I'm using.
|
||||
void *malloc(size_t size)
|
||||
{
|
||||
return m_malloc(size);
|
||||
}
|
||||
|
||||
void free(void *ptr)
|
||||
{
|
||||
m_free(ptr);
|
||||
}
|
||||
|
||||
void *realloc(void *ptr, size_t size)
|
||||
{
|
||||
return m_realloc(ptr, size);
|
||||
}
|
||||
|
||||
// EOF
|
||||
9
stm32/COLDCARD_Q1/modckcc.h
Normal file
9
stm32/COLDCARD_Q1/modckcc.h
Normal file
@ -0,0 +1,9 @@
|
||||
/*
|
||||
* (c) Copyright 2018 by Coinkite Inc. This file is covered by license found in COPYING-CC.
|
||||
*/
|
||||
#ifndef MICROPY_INCLUDED_STMHAL_MODCKCC_H
|
||||
#define MICROPY_INCLUDED_STMHAL_MODCKCC_H
|
||||
|
||||
#include "py/obj.h"
|
||||
|
||||
#endif // MICROPY_INCLUDED_STMHAL_MODCKCC_H
|
||||
128
stm32/COLDCARD_Q1/mpconfigboard.h
Normal file
128
stm32/COLDCARD_Q1/mpconfigboard.h
Normal file
@ -0,0 +1,128 @@
|
||||
/*
|
||||
* (c) Copyright 2018 by Coinkite Inc. This file is covered by license found in COPYING-CC.
|
||||
*/
|
||||
|
||||
#define MICROPY_HW_BOARD_NAME "Coldcard"
|
||||
#define MICROPY_PY_SYS_PLATFORM "coldcard"
|
||||
|
||||
#define MICROPY_HW_MCU_NAME "STM32L4SxVI"
|
||||
|
||||
#define MICROPY_HW_HAS_SWITCH (0)
|
||||
#define MICROPY_HW_HAS_FLASH (1)
|
||||
#define MICROPY_HW_HAS_SDCARD (1)
|
||||
#define MICROPY_HW_HAS_LCD (0)
|
||||
#define MICROPY_HW_ENABLE_HW_I2C (1)
|
||||
|
||||
// don't want, but lots of modules interdepend on this
|
||||
#define MICROPY_HW_ENABLE_RTC (0)
|
||||
|
||||
//#define HSE_VALUE ((uint32_t)8000000) /*!< Value of the External oscillator in Hz */
|
||||
|
||||
// USB config
|
||||
#define MICROPY_HW_ENABLE_USB (1)
|
||||
#define MICROPY_HW_USB_FS (1)
|
||||
|
||||
// HSE is used and is 8MHz
|
||||
// see hardcoding in clocks.c / bootrom / these values are not used / may be wrong
|
||||
#define MICROPY_HW_CLK_PLLN (40)
|
||||
#define MICROPY_HW_CLK_PLLM (2)
|
||||
#define MICROPY_HW_CLK_PLLR (2)
|
||||
#define MICROPY_HW_CLK_PLLP (7)
|
||||
#define MICROPY_HW_CLK_PLLQ (4)
|
||||
|
||||
#define MICROPY_HW_FLASH_LATENCY FLASH_LATENCY_4
|
||||
|
||||
// UART config
|
||||
#define MICROPY_HW_UART4_TX (pin_A0)
|
||||
#define MICROPY_HW_UART4_RX (pin_A0)
|
||||
#define MICROPY_HW_UART2_TX (pin_A2)
|
||||
#define MICROPY_HW_UART2_RX (pin_A2)
|
||||
#define MICROPY_HW_UART1_TX (pin_A9)
|
||||
#define MICROPY_HW_UART1_RX (pin_A10)
|
||||
|
||||
// Mk4 has real debug serial port, wonderful.
|
||||
#define MICROPY_HW_UART_REPL PYB_UART_1
|
||||
#define MICROPY_HW_UART_REPL_BAUD 115200
|
||||
|
||||
/* I2C busses: 2 */
|
||||
#define MICROPY_HW_I2C1_SCL (pin_B6)
|
||||
#define MICROPY_HW_I2C1_SDA (pin_B7)
|
||||
#define MICROPY_HW_I2C2_SCL (pin_B13)
|
||||
#define MICROPY_HW_I2C2_SDA (pin_B14)
|
||||
/*
|
||||
#define MICROPY_HW_I2C3_SCL (pin_C0)
|
||||
#define MICROPY_HW_I2C3_SDA (pin_C1)
|
||||
*/
|
||||
|
||||
// SPI busses (one)
|
||||
#define MICROPY_HW_SPI1_SCK (pin_A5)
|
||||
#define MICROPY_HW_SPI1_MOSI (pin_A7)
|
||||
//#define MICROPY_HW_SPI1_NSS (pin_A4)
|
||||
//#define MICROPY_HW_SPI1_MISO (pin_A6)
|
||||
|
||||
/* removed in Mk4 rev B
|
||||
#define MICROPY_HW_SPI2_NSS (pin_B9)
|
||||
#define MICROPY_HW_SPI2_SCK (pin_B10)
|
||||
#define MICROPY_HW_SPI2_MISO (pin_C2)
|
||||
#define MICROPY_HW_SPI2_MOSI (pin_C3)
|
||||
*/
|
||||
|
||||
// SD card detect switch
|
||||
// - open when card inserted, grounded when no card
|
||||
#define MICROPY_HW_SDCARD_DETECT_PIN (pin_C13)
|
||||
#define MICROPY_HW_SDCARD_DETECT_PULL (GPIO_PULLUP)
|
||||
#define MICROPY_HW_SDCARD_DETECT_PRESENT (GPIO_PIN_SET)
|
||||
|
||||
|
||||
// We have our own version of this code.
|
||||
#define MICROPY_HW_ENABLE_RNG (0)
|
||||
|
||||
extern void ckcc_early_init(void);
|
||||
#define MICROPY_BOARD_EARLY_INIT ckcc_early_init
|
||||
|
||||
// Need CRC32 for 7z support.
|
||||
#define MICROPY_PY_UBINASCII_CRC32 (1)
|
||||
|
||||
// Experiment, works.
|
||||
//#define MICROPY_STACKLESS (1)
|
||||
|
||||
#define USBD_MANUFACTURER_STRING "Coinkite"
|
||||
#define USBD_PRODUCT_HS_STRING "Coldcard Wallet"
|
||||
#define USBD_PRODUCT_FS_STRING "Coldcard Wallet"
|
||||
#define USBD_CONFIGURATION_HS_STRING "HS Config"
|
||||
#define USBD_INTERFACE_HS_STRING "HS Interface"
|
||||
#define USBD_CONFIGURATION_FS_STRING "FS Config"
|
||||
#define USBD_INTERFACE_FS_STRING "FS Interface"
|
||||
|
||||
// Where the heap should end up.
|
||||
extern void *ckcc_heap_start(void);
|
||||
extern void *ckcc_heap_end(void);
|
||||
#define MICROPY_HEAP_START ckcc_heap_start()
|
||||
#define MICROPY_HEAP_END ckcc_heap_end()
|
||||
|
||||
// Features/or not.
|
||||
#define MICROPY_HW_ENABLE_DHT (0)
|
||||
#define MICROPY_HW_ENABLE_ADC (0)
|
||||
|
||||
// override some boot-up stuff
|
||||
#define MICROPY_BOARD_BEFORE_BOOT_PY ckcc_boardctrl_before_boot_py
|
||||
#define MICROPY_BOARD_AFTER_BOOT_PY ckcc_boardctrl_after_boot_py
|
||||
|
||||
struct _boardctrl_state_t;
|
||||
extern void ckcc_boardctrl_before_boot_py(struct _boardctrl_state_t *state);
|
||||
extern void ckcc_boardctrl_after_boot_py(struct _boardctrl_state_t *state);
|
||||
|
||||
#define MICROPY_HW_SDCARD_MOUNT_AT_BOOT (0)
|
||||
|
||||
#define MICROPY_HW_ENABLE_SDCARD (1)
|
||||
#define MICROPY_HW_ENABLE_CARD_IDENT (1)
|
||||
|
||||
// called from usb.c to setup customized MSC storage
|
||||
struct _usbd_cdc_msc_hid_state_t;
|
||||
extern void psramdisk_USBD_MSC_RegisterStorage(int num_lun, struct _usbd_cdc_msc_hid_state_t *usbd);
|
||||
#define MICROPY_HW_CUSTOM_USB_MSC psramdisk_USBD_MSC_RegisterStorage
|
||||
|
||||
// enable some code inside oofatfs that we need
|
||||
#define FF_USE_FASTSEEK (1)
|
||||
|
||||
// EOF
|
||||
98
stm32/COLDCARD_Q1/mpconfigboard.mk
Normal file
98
stm32/COLDCARD_Q1/mpconfigboard.mk
Normal file
@ -0,0 +1,98 @@
|
||||
# Config for our board.
|
||||
#
|
||||
MCU_SERIES = l4
|
||||
CMSIS_MCU = STM32L4S5xx
|
||||
AF_FILE = boards/$(BOARD)/stm32l4s5_af.csv
|
||||
LD_FILES = boards/$(BOARD)/layout.ld boards/common_ifs.ld
|
||||
OPENOCD_CONFIG = boards/openocd_stm32l4.cfg
|
||||
|
||||
# MicroPython settings
|
||||
MICROPY_VFS_LFS2 = 1
|
||||
MICROPY_VFS_FAT = 1
|
||||
|
||||
# see py/mpconfig.h which uses this var if set
|
||||
CFLAGS_EXTRA += -DMP_CONFIGFILE=\"boards/$(BOARD)/ckcc-port.h\"
|
||||
CFLAGS_EXTRA += -DCOLDCARD_DEBUG=$(DEBUG_BUILD)
|
||||
|
||||
# obsolete
|
||||
# need the CDC inf file to be built before this file
|
||||
#initfs.c: $(GEN_CDCINF_HEADER)
|
||||
|
||||
# NgU and uQR libraries
|
||||
NGU_NEEDS_CIFRA = 1
|
||||
USER_C_MODULES = boards/$(BOARD)/c-modules
|
||||
|
||||
# the bulk of the COLDCARD-specific code
|
||||
# - do not want contents of stm32/boards/manifest.py
|
||||
FROZEN_MANIFEST = \
|
||||
boards/$(BOARD)/shared/manifest.py \
|
||||
boards/$(BOARD)/shared/manifest_mk4.py
|
||||
|
||||
# This will relocate things up by 128k=0x2_0000
|
||||
# see also ./layout.ld
|
||||
CFLAGS_MOD += -DVECT_TAB_OFFSET=0x20000
|
||||
TEXT0_ADDR = 0x08020000
|
||||
TEXT1_ADDR = 0x08024000
|
||||
|
||||
# don't want any of these: soft_spi, soft_qspi, dht
|
||||
#DRIVERS_SRC_C -= drivers/bus/softspi.c \
|
||||
# drivers/bus/softqspi.c drivers/memory/spiflash.c \
|
||||
# drivers/dht/dht.c
|
||||
|
||||
# Approximately all the source code files?
|
||||
ALL_SRC = $(SRC_LIB) $(SRC_LIBM) $(EXTMOD_SRC_C) $(DRIVERS_SRC_C) \
|
||||
$(SRC_HAL) $(SRC_USBDEV) $(SRC_MOD)
|
||||
ALL_SRC += $(addprefix ports/stm32/, $(SRC_C))
|
||||
ALL_SRC += py/*.[ch]
|
||||
|
||||
# XXX: this barely works, ignore errors
|
||||
tags:
|
||||
echo $(ALL_SRC)
|
||||
(cd $(TOP)/../..; pwd; ctags -R -f .tags $(addprefix external/micropython/, $(ALL_SRC)) \
|
||||
external/micropython/lib/stm32lib/STM32L4xx_HAL_Driver/*/*.[ch] \
|
||||
external/micropython/lib/stm32lib/CMSIS/STM32L4xx/Include/stm32l475xx.h \
|
||||
external/micropython/lib/cmsis/inc/core_cm4.h \
|
||||
external/micropython/ports/stm32/*.[ch] \
|
||||
external/micropython/ports/stm32/*/*.[ch] \
|
||||
external/micropython/ports/stm32/usbdev/{core,class}/{src,inc}/*.[ch] \
|
||||
external/libngu/ngu/*.[ch])
|
||||
sed -i .tmp '/dynruntime./d' $(TOP)/../../.tags
|
||||
|
||||
|
||||
checksum:
|
||||
$(OBJCOPY) -O binary -j .isr_vector -j .text -j .data \
|
||||
--pad-to 0x080e0000 --gap-fill 0xff \
|
||||
$(BUILD)/firmware.elf $(BUILD)/firmware-complete.bin
|
||||
shasum -a 256 $(BUILD)/firmware-complete.bin
|
||||
|
||||
# This costs about 241,136 of flash! Not clear on what I gain.
|
||||
# It enables -O0 instead of -Os!! Very bad.
|
||||
#DEBUG = 1
|
||||
|
||||
# we always want debug symbols, since they get stripped anyway
|
||||
COPT += -g
|
||||
|
||||
# bugfix IIRC
|
||||
build-COLDCARD_MK4/boards/COLDCARD_MK4/modckcc.o: COPT = -O0 -DNDEBUG
|
||||
|
||||
# pickiness
|
||||
build-COLDCARD_MK4/dma.o: COPT=-Werror=unused-const-variable=0
|
||||
build-COLDCARD_MK4/boards/COLDCARD_MK4/psramdisk.o: COPT=-Werror=unused-const-variable=0
|
||||
|
||||
# bugfix: remove unwanted setup code called from ports/stm32/resethandler.s
|
||||
build-COLDCARD_MK4/lib/stm32lib/CMSIS/STM32L4xx/Source/Templates/system_stm32l4xx.o: \
|
||||
CFLAGS += -DSystemInit=SystemInit_OMIT
|
||||
|
||||
# bugfix: replace keyboard interrupt handling
|
||||
build-COLDCARD_MK4/lib/utils/interrupt_char.o: \
|
||||
CFLAGS += -Dmp_hal_set_interrupt_char=mp_hal_set_interrupt_char_OMIT
|
||||
|
||||
|
||||
files:
|
||||
# SRC_C: $(SRC_C)
|
||||
@echo
|
||||
# SRC_HAL: $(SRC_HAL)
|
||||
@echo
|
||||
# CFLAGS: $(CFLAGS)
|
||||
@echo
|
||||
# FROZEN_MANIFEST: $(FROZEN_MANIFEST)
|
||||
91
stm32/COLDCARD_Q1/pins.csv
Normal file
91
stm32/COLDCARD_Q1/pins.csv
Normal file
@ -0,0 +1,91 @@
|
||||
D0,PA3
|
||||
D1,PA2
|
||||
D2,PA10
|
||||
D3,PB3
|
||||
D4,PB5
|
||||
D5,PB4
|
||||
D6,PB10
|
||||
D7,PA8
|
||||
D8,PA9
|
||||
D9,PC7
|
||||
D10,PB6
|
||||
D11,PA7
|
||||
D12,PA6
|
||||
D13,PA5
|
||||
D14,PB9
|
||||
D15,PB8
|
||||
PA0,PA0
|
||||
PA1,PA1
|
||||
PA2,PA2
|
||||
PA3,PA3
|
||||
PA4,PA4
|
||||
PA5,PA5
|
||||
PA6,PA6
|
||||
PA7,PA7
|
||||
PA8,PA8
|
||||
PA9,PA9
|
||||
PA10,PA10
|
||||
PA15,PA15
|
||||
PB0,PB0
|
||||
PB1,PB1
|
||||
PB2,PB2
|
||||
PB3,PB3
|
||||
PB4,PB4
|
||||
PB5,PB5
|
||||
PB6,PB6
|
||||
PB7,PB7
|
||||
PB8,PB8
|
||||
PB9,PB9
|
||||
PB10,PB10
|
||||
PB11,PB11
|
||||
PB12,PB12
|
||||
PB13,PB13
|
||||
PB14,PB14
|
||||
PB15,PB15
|
||||
PC0,PC0
|
||||
PC1,PC1
|
||||
PC2,PC2
|
||||
PC3,PC3
|
||||
PC4,PC4
|
||||
PC5,PC5
|
||||
PC6,PC6
|
||||
PC7,PC7
|
||||
PC8,PC8
|
||||
PC9,PC9
|
||||
PC10,PC10
|
||||
PC11,PC11
|
||||
PC12,PC12
|
||||
PC13,PC13
|
||||
PC14,PC14
|
||||
PC15,PC15
|
||||
PD2,PD2
|
||||
PH0,PH0
|
||||
PH1,PH1
|
||||
USB_DM,PA11
|
||||
USB_DP,PA12
|
||||
SD_D0,PC8
|
||||
SD_D1,PC9
|
||||
SD_D2,PC10
|
||||
SD_D3,PC11
|
||||
SD_CMD,PD2
|
||||
SD_CK,PC12
|
||||
SD_SW,PC13
|
||||
SD,PA9
|
||||
M2_COL0,PB0
|
||||
M2_COL1,PB1
|
||||
M2_COL2,PB2
|
||||
M2_ROW0,PD8
|
||||
M2_ROW1,PD9
|
||||
M2_ROW2,PD10
|
||||
M2_ROW3,PD11
|
||||
F_CS,PB9
|
||||
SF_SCLK,PB10
|
||||
SF_MISO,PC2
|
||||
SF_MOSI,PC3
|
||||
SD_ACTIVE,PC7
|
||||
USB_ACTIVE,PC6
|
||||
SE2_SCL,PB13
|
||||
SE2_SDA,PB14
|
||||
NFC_SCL,PB6
|
||||
NFC_SDA,PB7
|
||||
NFC_ED,PC4
|
||||
|
792
stm32/COLDCARD_Q1/psramdisk.c
Normal file
792
stm32/COLDCARD_Q1/psramdisk.c
Normal file
@ -0,0 +1,792 @@
|
||||
/*
|
||||
* (c) Copyright 2021 by Coinkite Inc. This file is covered by license found in COPYING-CC.
|
||||
*
|
||||
* Implement a ram disk in PSRAM, accessible by host as MSC and mpy as block dev.
|
||||
*
|
||||
*/
|
||||
#include <stdint.h>
|
||||
|
||||
#include "usbd_cdc_msc_hid.h"
|
||||
#include "usbd_msc_interface.h"
|
||||
#include "usbd_cdc_msc_hid0.h"
|
||||
#include "usbd_msc_bot.h"
|
||||
#include "usbd_msc_scsi.h"
|
||||
#include "usbd_ioreq.h"
|
||||
#include "py/gc.h"
|
||||
#include "py/mphal.h"
|
||||
#include "py/runtime.h"
|
||||
#include "extmod/vfs.h"
|
||||
#include "extmod/vfs_fat.h"
|
||||
#include "lib/oofatfs/ff.h"
|
||||
#include "py/runtime.h"
|
||||
#include "py/mperrno.h"
|
||||
#include "softtimer.h"
|
||||
#include "ulight.h"
|
||||
|
||||
// Our storage, in quad-serial SPI PSRAM chip
|
||||
// - using top half of chip only
|
||||
static uint8_t *PSRAM_TOP_BASE = (uint8_t *)0x90400000; // OCTOSPI mapping, top half
|
||||
static uint8_t *PSRAM_BOT_BASE = (uint8_t *)0x90000000; // OCTOSPI mapping, bot half
|
||||
static const uint32_t PSRAM_SIZE = 0x400000; // 4 megs (half)
|
||||
static const uint32_t BLOCK_SIZE = 512;
|
||||
static const uint32_t BLOCK_COUNT = PSRAM_SIZE / BLOCK_SIZE; // = 8192
|
||||
|
||||
extern __IO uint32_t uwTick;
|
||||
|
||||
// this code will always be the first LUN
|
||||
static const uint8_t MY_LUN = 0;
|
||||
|
||||
STATIC mp_obj_t psram_wipe_and_setup(mp_obj_t unused_self);
|
||||
STATIC const uint8_t psram_msc_lu_num = 1;
|
||||
|
||||
typedef struct _psram_obj_t {
|
||||
mp_obj_base_t base;
|
||||
|
||||
uint32_t host_write_time;
|
||||
} psram_obj_t;
|
||||
|
||||
// singleton
|
||||
const mp_obj_type_t psram_type;
|
||||
psram_obj_t psram_obj = {
|
||||
{ &psram_type },
|
||||
};
|
||||
|
||||
#define HOST_WR_TIMEOUT 750 // (ms)
|
||||
static soft_timer_entry_t host_wr_done;
|
||||
|
||||
// we only have a single LUN, so flags can be simple
|
||||
// - note that "started" is more like inserted vs. ejected
|
||||
bool flag_STARTED = false;
|
||||
bool flag_READONLY = false;
|
||||
|
||||
// psram_init()
|
||||
//
|
||||
void
|
||||
psram_init(void)
|
||||
{
|
||||
// always clear and reset contents
|
||||
psram_wipe_and_setup(NULL);
|
||||
|
||||
//mp_pairheap_t pairheap;
|
||||
host_wr_done.mode = SOFT_TIMER_MODE_ONE_SHOT;
|
||||
host_wr_done.expiry_ms = HOST_WR_TIMEOUT;
|
||||
host_wr_done.callback = MP_ROM_NONE;
|
||||
host_wr_done.pairheap.base.type = &psram_type; // callback gets this object as only arg
|
||||
}
|
||||
|
||||
// reset_wr_timeout()
|
||||
//
|
||||
static void
|
||||
reset_wr_timeout(void)
|
||||
{
|
||||
// host has written something, reset/set a timeout to look at new change,
|
||||
// assuming more is not written before the timeout expires.
|
||||
|
||||
soft_timer_remove(&host_wr_done);
|
||||
|
||||
psram_obj.host_write_time = uwTick;
|
||||
|
||||
if(host_wr_done.callback != MP_ROM_NONE) {
|
||||
host_wr_done.expiry_ms = uwTick + HOST_WR_TIMEOUT;
|
||||
soft_timer_insert(&host_wr_done);
|
||||
}
|
||||
}
|
||||
|
||||
// wr_timeout_now()
|
||||
//
|
||||
static void
|
||||
wr_timeout_now(void)
|
||||
{
|
||||
// host did something that indicates it won't be writing anymore to
|
||||
// the disk, and therefore ok to immediately look at contents.
|
||||
|
||||
soft_timer_remove(&host_wr_done);
|
||||
|
||||
psram_obj.host_write_time = uwTick;
|
||||
|
||||
if(host_wr_done.callback != MP_ROM_NONE) {
|
||||
mp_sched_schedule(host_wr_done.callback, MP_OBJ_FROM_PTR(&psram_obj));
|
||||
}
|
||||
}
|
||||
|
||||
// block_to_ptr()
|
||||
//
|
||||
static uint8_t *
|
||||
block_to_ptr(uint32_t blk, uint16_t num_blk)
|
||||
{
|
||||
// Range checking on incoming requests also done in SCSI_CheckAddressRange()
|
||||
// but this is an extra layer of safety, important since we might expose
|
||||
// our address space otherwise!
|
||||
// - note unsigned arguments
|
||||
|
||||
if(blk >= BLOCK_COUNT) return NULL;
|
||||
if((blk+num_blk) > BLOCK_COUNT) return NULL;
|
||||
|
||||
return &PSRAM_TOP_BASE[blk * BLOCK_SIZE];
|
||||
}
|
||||
|
||||
// Sent in response to MODE SENSE(6) command
|
||||
const uint8_t PSRAM_MSC_Mode_Sense6_Data[4] = {
|
||||
0x03, // mode data length
|
||||
0x00, // medium type
|
||||
0x00, // bit 7: write protect
|
||||
0x00, // block descriptor length
|
||||
};
|
||||
|
||||
// Sent in response to MODE SENSE(10) command
|
||||
const uint8_t PSRAM_MSC_Mode_Sense10_Data[8] = {
|
||||
0x00, 0x06, // mode data length
|
||||
0x00, // medium type
|
||||
0x00, // bit 7: write protect
|
||||
0x00,
|
||||
0x00,
|
||||
0x00, 0x00, // block descriptor length
|
||||
};
|
||||
|
||||
STATIC const uint8_t psram_msc_vpd00[6] = {
|
||||
0x00, // peripheral qualifier; peripheral device type
|
||||
0x00, // page code
|
||||
0x00, // reserved
|
||||
2, // page length (additional bytes beyond this entry)
|
||||
0x00, // page 0x00 supported
|
||||
0x83, // page 0x83 supported
|
||||
};
|
||||
|
||||
STATIC const uint8_t psram_msc_vpd83[4] = {
|
||||
0x00, // peripheral qualifier; peripheral device type
|
||||
0x83, // page code
|
||||
0x00, 0x00, // page length (additional bytes beyond this entry)
|
||||
};
|
||||
|
||||
STATIC const int8_t psram_msc_inquiry_data[36] = {
|
||||
0x00, // peripheral qualifier; peripheral device type
|
||||
0x80, // 0x00 for a fixed drive, 0x80 for a removable drive
|
||||
0x02, // version
|
||||
0x02, // response data format
|
||||
(STANDARD_INQUIRY_DATA_LEN - 5), // additional length
|
||||
0x00, // various flags
|
||||
0x00, // various flags
|
||||
0x00, // various flags
|
||||
'C', 'o', 'i', 'n', 'k', 'i', 't', 'e', // Manufacturer : 8 bytes
|
||||
'C', 'O', 'L', 'D', 'C', 'A', 'R', 'D', // Product : 16 Bytes
|
||||
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
|
||||
'4', '.', '0','0', // Version : 4 Bytes
|
||||
};
|
||||
|
||||
// Initialise all logical units (it's only ever called once, with lun_in=0)
|
||||
STATIC int8_t psram_msc_Init(uint8_t lun_in)
|
||||
{
|
||||
if(lun_in != MY_LUN) return -1;
|
||||
|
||||
// don't change flag here, might have been set by python
|
||||
//flags_STARTED = false;
|
||||
//flags_READONLY = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Process SCSI INQUIRY command for the logical unit
|
||||
STATIC int psram_msc_Inquiry(uint8_t lun, const uint8_t *params, uint8_t *data_out)
|
||||
{
|
||||
if(lun != MY_LUN) return -1;
|
||||
|
||||
ckcc_usb_active = true;
|
||||
|
||||
if (params[1] & 1) {
|
||||
// EVPD set - return vital product data parameters
|
||||
uint8_t page_code = params[2];
|
||||
|
||||
switch (page_code) {
|
||||
case 0x00: // Supported VPD pages
|
||||
memcpy(data_out, psram_msc_vpd00, sizeof(psram_msc_vpd00));
|
||||
return sizeof(psram_msc_vpd00);
|
||||
|
||||
case 0x83: // Device identification
|
||||
memcpy(data_out, psram_msc_vpd83, sizeof(psram_msc_vpd83));
|
||||
return sizeof(psram_msc_vpd83);
|
||||
|
||||
default: // Unsupported
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// A standard inquiry
|
||||
uint16_t alloc_len = params[3] << 8 | params[4];
|
||||
int len = MIN(sizeof(psram_msc_inquiry_data), alloc_len);
|
||||
memcpy(data_out, psram_msc_inquiry_data, len);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
// Get storage capacity of a logical unit
|
||||
STATIC int8_t psram_msc_GetCapacity(uint8_t lun, uint32_t *block_num, uint16_t *block_size)
|
||||
{
|
||||
// might be important not to write to pointers if unexpected LUN
|
||||
if(lun != MY_LUN) return -1;
|
||||
|
||||
ckcc_usb_active = true;
|
||||
|
||||
*block_num = BLOCK_COUNT;
|
||||
*block_size = BLOCK_SIZE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Check if a logical unit is ready
|
||||
STATIC int8_t psram_msc_IsReady(uint8_t lun)
|
||||
{
|
||||
if(lun != MY_LUN) return -1;
|
||||
|
||||
// NOTE: called frequently, and must be T for MacOS to recognize at all
|
||||
// when F, macos keeps trying to work until it's ready again (freezing programs
|
||||
// trying to work with the drive).
|
||||
return flag_STARTED ? 0 : -1;
|
||||
}
|
||||
|
||||
// Check if a logical unit is write protected
|
||||
STATIC int8_t psram_msc_IsWriteProtected(uint8_t lun)
|
||||
{
|
||||
if(lun != MY_LUN) return -1;
|
||||
|
||||
return flag_READONLY ? 1 : 0;
|
||||
}
|
||||
|
||||
// Start or stop a logical unit
|
||||
STATIC int8_t psram_msc_StartStopUnit(uint8_t lun, uint8_t started)
|
||||
{
|
||||
if(lun != MY_LUN) return -1;
|
||||
|
||||
// host is not allowed to change our ready status: always fail
|
||||
//printf("PSRAMdisk: started=%d tried\n", started);
|
||||
ckcc_usb_active = true;
|
||||
|
||||
if(!started) {
|
||||
// (macos) is trying to "eject" the disk. Note this event.
|
||||
wr_timeout_now();
|
||||
}
|
||||
|
||||
return -1;
|
||||
#if 0
|
||||
if (started) {
|
||||
flag_STARTED = true;
|
||||
ckcc_usb_active = true;
|
||||
} else {
|
||||
flag_STARTED = false;
|
||||
}
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Prepare a logical unit for possible removal
|
||||
STATIC int8_t psram_msc_PreventAllowMediumRemoval(uint8_t lun, uint8_t param)
|
||||
{
|
||||
if(lun != MY_LUN) return -1;
|
||||
|
||||
//printf("PSRAMdisk: prevallow=%d\n", param);
|
||||
if(param == 0) {
|
||||
// allow removal == host is done (like after umount in MacOS)
|
||||
wr_timeout_now();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Read data from a logical unit
|
||||
STATIC int8_t psram_msc_Read(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len)
|
||||
{
|
||||
if(lun != MY_LUN) return -1;
|
||||
|
||||
ckcc_usb_active = true;
|
||||
|
||||
uint8_t *ptr = block_to_ptr(blk_addr, blk_len);
|
||||
if(!ptr) return -1;
|
||||
|
||||
memcpy(buf, ptr, blk_len*BLOCK_SIZE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Write data to a logical unit
|
||||
STATIC int8_t psram_msc_Write(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len)
|
||||
{
|
||||
if(lun != MY_LUN) return -1;
|
||||
|
||||
ckcc_usb_active = true;
|
||||
|
||||
uint8_t *ptr = block_to_ptr(blk_addr, blk_len);
|
||||
if(!ptr) return -1;
|
||||
|
||||
memcpy(ptr, buf, blk_len*BLOCK_SIZE);
|
||||
|
||||
reset_wr_timeout();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Get the number of attached logical units
|
||||
STATIC int8_t psram_msc_GetMaxLun(void) {
|
||||
ckcc_usb_active = true;
|
||||
|
||||
return psram_msc_lu_num - 1;
|
||||
}
|
||||
|
||||
|
||||
// Table of operations for the SCSI layer to call
|
||||
USBD_StorageTypeDef psramdisk_fops = {
|
||||
psram_msc_Init,
|
||||
psram_msc_Inquiry,
|
||||
psram_msc_GetCapacity,
|
||||
psram_msc_IsReady,
|
||||
psram_msc_IsWriteProtected,
|
||||
psram_msc_StartStopUnit,
|
||||
psram_msc_PreventAllowMediumRemoval,
|
||||
psram_msc_Read,
|
||||
psram_msc_Write,
|
||||
psram_msc_GetMaxLun,
|
||||
};
|
||||
|
||||
void psramdisk_USBD_MSC_RegisterStorage(int num_lun, usbd_cdc_msc_hid_state_t *usbd) {
|
||||
// equiv to usbdev/class/inc/usbd_cdc_msc_hid.h
|
||||
usbd->MSC_BOT_ClassData.bdev_ops = &psramdisk_fops;
|
||||
//mp_printf(&mp_plat_print, "PSRAMdisk: activated\n");
|
||||
}
|
||||
|
||||
//
|
||||
// mpy user interface: os.AbstractBlockDev interface
|
||||
//
|
||||
// see <https://docs.micropython.org/en/latest/library/uos.html#simple-and-extended-interface>
|
||||
//
|
||||
|
||||
|
||||
STATIC void psram_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
|
||||
mp_printf(print, "PSRAM()");
|
||||
}
|
||||
|
||||
STATIC mp_obj_t psram_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
|
||||
// Parse arguments: none allowed
|
||||
mp_arg_parse_all_kw_array(n_args, n_kw, all_args, 0, NULL, NULL);
|
||||
|
||||
// singleton, we take no args
|
||||
return MP_OBJ_FROM_PTR(&psram_obj);
|
||||
}
|
||||
|
||||
STATIC mp_obj_t psram_readblocks(size_t n_args, const mp_obj_t *args) {
|
||||
//psram_obj_t *self = MP_OBJ_TO_PTR(args[0]);
|
||||
uint32_t block_num = mp_obj_get_int(args[1]);
|
||||
|
||||
mp_buffer_info_t bufinfo;
|
||||
mp_get_buffer_raise(args[2], &bufinfo, MP_BUFFER_WRITE);
|
||||
|
||||
// Full range check; not supporting partial blocks nor offsets
|
||||
uint16_t blk_len = bufinfo.len / BLOCK_SIZE;
|
||||
if(blk_len < 1) goto fail;
|
||||
if((blk_len * BLOCK_SIZE) != bufinfo.len) goto fail;
|
||||
|
||||
uint8_t *ptr = block_to_ptr(block_num, blk_len);
|
||||
if(!ptr) goto fail;
|
||||
|
||||
memcpy(bufinfo.buf, ptr, bufinfo.len);
|
||||
|
||||
return MP_OBJ_NEW_SMALL_INT(0);
|
||||
fail:
|
||||
mp_raise_ValueError(NULL);
|
||||
return mp_const_none; // not reached
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(psram_readblocks_obj, 3, 3, psram_readblocks);
|
||||
|
||||
STATIC mp_obj_t psram_writeblocks(size_t n_args, const mp_obj_t *args) {
|
||||
//psram_obj_t *self = MP_OBJ_TO_PTR(args[0]);
|
||||
uint32_t block_num = mp_obj_get_int(args[1]);
|
||||
|
||||
mp_buffer_info_t bufinfo;
|
||||
mp_get_buffer_raise(args[2], &bufinfo, MP_BUFFER_READ);
|
||||
|
||||
// Full range check; not supporting partial blocks nor offsets
|
||||
uint16_t blk_len = bufinfo.len / BLOCK_SIZE;
|
||||
if(blk_len < 1) goto fail;
|
||||
if((blk_len * BLOCK_SIZE) != bufinfo.len) goto fail;
|
||||
|
||||
uint8_t *ptr = block_to_ptr(block_num, blk_len);
|
||||
if(!ptr) goto fail;
|
||||
|
||||
memcpy(ptr, bufinfo.buf, bufinfo.len);
|
||||
|
||||
return MP_OBJ_NEW_SMALL_INT(0);
|
||||
fail:
|
||||
mp_raise_ValueError(NULL);
|
||||
return mp_const_none; // not reached
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(psram_writeblocks_obj, 3, 3, psram_writeblocks);
|
||||
|
||||
int direct_psram_read_blocks(uint8_t *dest, uint32_t block_num, uint32_t num_blocks) {
|
||||
// Return zero or -MP_EIO
|
||||
uint8_t *ptr = block_to_ptr(block_num, num_blocks);
|
||||
if(!ptr) return -MP_EIO;
|
||||
|
||||
memcpy(dest, ptr, num_blocks * BLOCK_SIZE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
int direct_psram_write_blocks(const uint8_t *src, uint32_t block_num, uint32_t num_blocks) {
|
||||
// Return zero or -MP_EIO
|
||||
uint8_t *ptr = block_to_ptr(block_num, num_blocks);
|
||||
if(!ptr) return -MP_EIO;
|
||||
|
||||
memcpy(ptr, src, num_blocks * BLOCK_SIZE);
|
||||
|
||||
// Need some recovery time here for PSRAM or QUADSPI module. Otherwise, lockup!
|
||||
asm("nop");
|
||||
asm("nop");
|
||||
asm("nop");
|
||||
asm("nop");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
STATIC mp_obj_t psram_ioctl(mp_obj_t self_in, mp_obj_t cmd_in, mp_obj_t arg_in) {
|
||||
//psram_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
mp_int_t cmd = mp_obj_get_int(cmd_in);
|
||||
|
||||
switch (cmd) {
|
||||
case MP_BLOCKDEV_IOCTL_SYNC:
|
||||
// umount() called; CC done w/ filesystem
|
||||
return MP_OBJ_NEW_SMALL_INT(0);
|
||||
|
||||
case MP_BLOCKDEV_IOCTL_INIT: // when mount() happens (even R/O)
|
||||
case MP_BLOCKDEV_IOCTL_DEINIT: // not observed
|
||||
// nothing to do
|
||||
return MP_OBJ_NEW_SMALL_INT(0);
|
||||
|
||||
case MP_BLOCKDEV_IOCTL_BLOCK_COUNT:
|
||||
return MP_OBJ_NEW_SMALL_INT(BLOCK_COUNT);
|
||||
|
||||
case MP_BLOCKDEV_IOCTL_BLOCK_SIZE:
|
||||
return MP_OBJ_NEW_SMALL_INT(BLOCK_SIZE);
|
||||
|
||||
case MP_BLOCKDEV_IOCTL_BLOCK_ERASE: {
|
||||
mp_int_t block_num = mp_obj_get_int(arg_in);
|
||||
|
||||
uint8_t *ptr = block_to_ptr(block_num, 1);
|
||||
if(!ptr) return mp_const_none;
|
||||
|
||||
memset(ptr, 0xff, BLOCK_SIZE);
|
||||
|
||||
return MP_OBJ_NEW_SMALL_INT(0);
|
||||
}
|
||||
|
||||
default:
|
||||
return mp_const_none;
|
||||
}
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_3(psram_ioctl_obj, psram_ioctl);
|
||||
|
||||
static void psram_init_vfs(fs_user_mount_t *vfs, bool readonly) {
|
||||
// Simulates mounting the block device into VFS system. Assumes FAT format.
|
||||
vfs->base.type = &mp_fat_vfs_type;
|
||||
vfs->blockdev.flags |= MP_BLOCKDEV_FLAG_NATIVE | MP_BLOCKDEV_FLAG_HAVE_IOCTL;
|
||||
|
||||
vfs->fatfs.drv = vfs;
|
||||
vfs->fatfs.part = 0; // no partions; we have no MBR, like a floppy
|
||||
vfs->blockdev.readblocks[0] = MP_OBJ_FROM_PTR(&psram_readblocks_obj);
|
||||
vfs->blockdev.readblocks[1] = MP_OBJ_FROM_PTR(&psram_obj);
|
||||
vfs->blockdev.readblocks[2] = MP_OBJ_FROM_PTR(direct_psram_read_blocks);
|
||||
if(!readonly) {
|
||||
vfs->blockdev.writeblocks[0] = MP_OBJ_FROM_PTR(&psram_writeblocks_obj);
|
||||
vfs->blockdev.writeblocks[1] = MP_OBJ_FROM_PTR(&psram_obj);
|
||||
vfs->blockdev.writeblocks[2] = MP_OBJ_FROM_PTR(direct_psram_write_blocks);
|
||||
}
|
||||
vfs->blockdev.u.ioctl[0] = MP_OBJ_FROM_PTR(&psram_ioctl_obj);
|
||||
vfs->blockdev.u.ioctl[1] = MP_OBJ_FROM_PTR(&psram_obj);
|
||||
}
|
||||
|
||||
mp_obj_t psram_wipe_and_setup(mp_obj_t unused_self)
|
||||
{
|
||||
// Erase and reformat filesystem
|
||||
// - you probably should unmount it, before calling this
|
||||
|
||||
// Wipe contents for security.
|
||||
memset(PSRAM_TOP_BASE, 0x21, BLOCK_SIZE * BLOCK_COUNT);
|
||||
|
||||
// Build obj to handle blockdev protocol
|
||||
fs_user_mount_t vfs = {0};
|
||||
psram_init_vfs(&vfs, false);
|
||||
|
||||
// newfs:
|
||||
// - FAT16 (auto)
|
||||
// - cluster=sector=512 to keep it simple
|
||||
// - FM_SFD=>start sector=0, not 63 "single partition" no MBR wastage
|
||||
uint8_t working_buf[FF_MAX_SS];
|
||||
FRESULT res = f_mkfs(&vfs.fatfs, FM_FAT|FM_SFD, BLOCK_SIZE, working_buf, sizeof(working_buf));
|
||||
if (res != FR_OK) {
|
||||
//mp_printf(&mp_plat_print, "PSRAM: can't create filesystem\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
// set volume label, which becomes mountpoint on MacOS
|
||||
// .. can't do this from python AFAIK
|
||||
f_setlabel(&vfs.fatfs, "COLDCARD");
|
||||
f_mkdir(&vfs.fatfs, "ident");
|
||||
|
||||
FIL fp;
|
||||
UINT n;
|
||||
|
||||
// create an ident file, or two
|
||||
// - algo matches shared/version.py serial_number() function
|
||||
{ char fname[80];
|
||||
const uint8_t *id = (const uint8_t *)MP_HAL_UNIQUE_ID_ADDRESS; // 12 bytes, binary
|
||||
snprintf(fname, sizeof(fname),
|
||||
"ident/ckcc-%02X%02X%02X%02X%02X%02X.txt",
|
||||
id[11], id[10] + id[2], id[9], id[8] + id[0], id[7], id[6]);
|
||||
const char *serial = &fname[11];
|
||||
|
||||
f_open(&vfs.fatfs, &fp, fname, FA_WRITE | FA_CREATE_ALWAYS);
|
||||
f_write(&fp, serial, 12, &n);
|
||||
f_write(&fp, "\r\n", 2, &n);
|
||||
f_close(&fp);
|
||||
|
||||
f_open(&vfs.fatfs, &fp, "ident/serial.txt", FA_WRITE | FA_CREATE_ALWAYS);
|
||||
f_write(&fp, serial, 12, &n);
|
||||
f_write(&fp, "\r\n", 2, &n);
|
||||
f_close(&fp);
|
||||
}
|
||||
|
||||
return mp_const_none;
|
||||
|
||||
fail:
|
||||
mp_raise_ValueError(NULL);
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(psram_wipe_obj, psram_wipe_and_setup);
|
||||
|
||||
// copy from lib/oofatfs/ff.c
|
||||
static DWORD clst2sect ( /* !=0:Sector number, 0:Failed (invalid cluster#) */
|
||||
FATFS* fs, /* Filesystem object */
|
||||
DWORD clst /* Cluster# to be converted */
|
||||
)
|
||||
{
|
||||
clst -= 2; /* Cluster number is origin from 2 */
|
||||
if (clst >= fs->n_fatent - 2) return 0; /* Is it invalid cluster number? */
|
||||
return fs->database + fs->csize * clst; /* Start sector number of the cluster */
|
||||
}
|
||||
|
||||
|
||||
mp_obj_t psram_mmap_file(mp_obj_t unused_self, mp_obj_t fname_in)
|
||||
{
|
||||
// Find a file inside a FATFS and return a list of tuples which
|
||||
// provide the physical locations/lengths of the bytes of the
|
||||
// file's contents. Effectively it's the mmap call.
|
||||
// - file path must be striped of mountpt
|
||||
const char *fname = mp_obj_str_get_str(fname_in);
|
||||
|
||||
// Build obj to handle python protocol
|
||||
fs_user_mount_t vfs = {0};
|
||||
psram_init_vfs(&vfs, true);
|
||||
|
||||
FRESULT res = f_mount(&vfs.fatfs);
|
||||
if (res != FR_OK) {
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("unmountable"));
|
||||
}
|
||||
|
||||
// open the file directly
|
||||
FIL fp = {0};
|
||||
if(f_open(&vfs.fatfs, &fp, fname, FA_READ) != FR_OK) {
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("file no open"));
|
||||
}
|
||||
|
||||
// see <http://elm-chan.org/fsw/ff/doc/lseek.html> to learn this magic
|
||||
DWORD mapping[64];
|
||||
mapping[0] = MP_ARRAY_SIZE(mapping);
|
||||
fp.cltbl = mapping;
|
||||
|
||||
int rv = f_lseek(&fp, CREATE_LINKMAP);
|
||||
if(rv != FR_OK) {
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("lseek"));
|
||||
}
|
||||
|
||||
// Convert and remap list of clusters
|
||||
|
||||
// import ckcc; ckcc.PSRAM().mmap('serial.txt')
|
||||
|
||||
int num_used = (mapping[0] - 1) / 2;
|
||||
if((num_used < 1) || (num_used >= MP_ARRAY_SIZE(mapping))) {
|
||||
mp_raise_ValueError(NULL);
|
||||
}
|
||||
DWORD *ptr = &mapping[1];
|
||||
|
||||
mp_obj_t tups[num_used];
|
||||
|
||||
uint32_t so_far = 0;
|
||||
for(int i=0; i<num_used; i++) {
|
||||
int num_clusters = *(ptr++);
|
||||
uint32_t cluster = *(ptr++);
|
||||
|
||||
uint8_t *spot = block_to_ptr(clst2sect(&vfs.fatfs, cluster), num_clusters);
|
||||
if(!spot) {
|
||||
//printf("[%d] (cl=0x%lx ln=%d) => ", i, cluster, num_clusters);
|
||||
//printf("0x%lx\n", clst2sect(&vfs.fatfs, cluster));
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("clstfck"));
|
||||
}
|
||||
uint32_t len = num_clusters*BLOCK_SIZE;
|
||||
|
||||
if(i == num_used-1) {
|
||||
// final cluster might include some bytes past the EOF
|
||||
len = fp.obj.objsize - so_far;
|
||||
} else {
|
||||
so_far += len;
|
||||
}
|
||||
|
||||
mp_obj_t here[2] = {
|
||||
mp_obj_new_int_from_uint((uint32_t)spot),
|
||||
MP_OBJ_NEW_SMALL_INT(len)
|
||||
};
|
||||
|
||||
tups[i] = mp_obj_new_tuple(2, here);
|
||||
|
||||
}
|
||||
f_close(&fp);
|
||||
|
||||
return mp_obj_new_list(num_used, tups);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(psram_mmap_file_obj, psram_mmap_file);
|
||||
|
||||
mp_obj_t psram_copy_file(mp_obj_t unused_self, mp_obj_t offset_in, mp_obj_t fname_in)
|
||||
{
|
||||
// Find a file inside a FATFS and copy it into another area of PSRAM.
|
||||
// - file path must be striped of mountpt
|
||||
uint32_t offset = mp_obj_get_int(offset_in); // checks below
|
||||
const char *fname = mp_obj_str_get_str(fname_in);
|
||||
|
||||
// Build obj to handle python protocol
|
||||
fs_user_mount_t vfs = {0};
|
||||
psram_init_vfs(&vfs, true);
|
||||
|
||||
FRESULT res = f_mount(&vfs.fatfs);
|
||||
if (res != FR_OK) {
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("unmountable"));
|
||||
}
|
||||
|
||||
// open the file directly
|
||||
FIL fp = {0};
|
||||
if(f_open(&vfs.fatfs, &fp, fname, FA_READ) != FR_OK) {
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("file no open"));
|
||||
}
|
||||
|
||||
// see <http://elm-chan.org/fsw/ff/doc/lseek.html> to learn this magic
|
||||
DWORD mapping[64];
|
||||
mapping[0] = MP_ARRAY_SIZE(mapping);
|
||||
fp.cltbl = mapping;
|
||||
|
||||
int rv = f_lseek(&fp, CREATE_LINKMAP);
|
||||
if(rv != FR_OK) {
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("lseek"));
|
||||
}
|
||||
|
||||
// Convert and remap list of clusters
|
||||
|
||||
int num_used = (mapping[0] - 1) / 2;
|
||||
if((num_used < 1) || (num_used >= MP_ARRAY_SIZE(mapping))) {
|
||||
mp_raise_ValueError(NULL);
|
||||
}
|
||||
|
||||
uint32_t actual_len = fp.obj.objsize;
|
||||
|
||||
// where we will put copy
|
||||
uint8_t *dest = PSRAM_BOT_BASE + offset;
|
||||
if(offset % 4) mp_raise_ValueError(NULL);
|
||||
if(((uint32_t)dest) % 4) mp_raise_ValueError(NULL);
|
||||
if(dest < PSRAM_BOT_BASE) mp_raise_ValueError(NULL);
|
||||
if(dest >= PSRAM_TOP_BASE) mp_raise_ValueError(NULL);
|
||||
if(dest+actual_len+3 >= PSRAM_TOP_BASE) mp_raise_ValueError(NULL);
|
||||
|
||||
uint32_t so_far = 0;
|
||||
DWORD *ptr = &mapping[1];
|
||||
for(int i=0; i<num_used; i++) {
|
||||
int num_clusters = *(ptr++);
|
||||
uint32_t cluster = *(ptr++);
|
||||
|
||||
uint8_t *spot = block_to_ptr(clst2sect(&vfs.fatfs, cluster), num_clusters);
|
||||
if(!spot) {
|
||||
//printf("[%d] (cl=0x%lx ln=%d) => ", i, cluster, num_clusters);
|
||||
//printf("0x%lx\n", clst2sect(&vfs.fatfs, cluster));
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("clstfck"));
|
||||
}
|
||||
uint32_t len = num_clusters*BLOCK_SIZE;
|
||||
|
||||
if(i == num_used-1) {
|
||||
// final cluster might include some bytes past the EOF
|
||||
len = actual_len - so_far;
|
||||
// align4
|
||||
len = (len + 3) & ~0x3;
|
||||
} else {
|
||||
so_far += len;
|
||||
}
|
||||
|
||||
memcpy(dest, spot, len);
|
||||
dest += len;
|
||||
|
||||
if(dest >= PSRAM_TOP_BASE) mp_raise_ValueError(NULL);
|
||||
}
|
||||
f_close(&fp);
|
||||
|
||||
return MP_OBJ_NEW_SMALL_INT(actual_len);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_3(psram_copy_file_obj, psram_copy_file);
|
||||
|
||||
mp_obj_t psram_set_callback(mp_obj_t unused_self, mp_obj_t callback_in)
|
||||
{
|
||||
// set or clear the callback, use None to disable
|
||||
soft_timer_remove(&host_wr_done);
|
||||
|
||||
host_wr_done.callback = callback_in;
|
||||
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(psram_set_callback_obj, psram_set_callback);
|
||||
|
||||
mp_obj_t psram_set_inserted(mp_obj_t unused_self, mp_obj_t enable_in)
|
||||
{
|
||||
// set or clear insertion status (media started)
|
||||
if(enable_in != MP_ROM_NONE) {
|
||||
bool enable = !!mp_obj_get_int(enable_in);
|
||||
|
||||
flag_STARTED = enable;
|
||||
}
|
||||
|
||||
return MP_OBJ_NEW_SMALL_INT(flag_STARTED);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(psram_set_inserted_obj, psram_set_inserted);
|
||||
|
||||
mp_obj_t psram_get_time(mp_obj_t unused_self)
|
||||
{
|
||||
// return time of last write from host
|
||||
|
||||
return mp_obj_new_int_from_uint(psram_obj.host_write_time);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(psram_get_time_obj, psram_get_time);
|
||||
|
||||
|
||||
STATIC const mp_rom_map_elem_t psram_locals_dict_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR_readblocks), MP_ROM_PTR(&psram_readblocks_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_writeblocks), MP_ROM_PTR(&psram_writeblocks_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_ioctl), MP_ROM_PTR(&psram_ioctl_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_wipe), MP_ROM_PTR(&psram_wipe_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_mmap), MP_ROM_PTR(&psram_mmap_file_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_copy_file), MP_ROM_PTR(&psram_copy_file_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_callback), MP_ROM_PTR(&psram_set_callback_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_set_inserted), MP_ROM_PTR(&psram_set_inserted_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_get_time), MP_ROM_PTR(&psram_get_time_obj) },
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(psram_locals_dict, psram_locals_dict_table);
|
||||
|
||||
// our block device object for Micropython
|
||||
const mp_obj_type_t psram_type = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_PSRAM,
|
||||
.print = psram_print,
|
||||
.make_new = psram_make_new,
|
||||
.locals_dict = (mp_obj_dict_t *)&psram_locals_dict,
|
||||
};
|
||||
|
||||
|
||||
// EOF
|
||||
152
stm32/COLDCARD_Q1/rng.c
Normal file
152
stm32/COLDCARD_Q1/rng.c
Normal file
@ -0,0 +1,152 @@
|
||||
/*
|
||||
* (c) Copyright 2018 by Coinkite Inc. This file is covered by license found in COPYING-CC.
|
||||
*
|
||||
* based on ../../rng.c but more paranoid
|
||||
*
|
||||
*/
|
||||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2013, 2014 Damien P. George
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "py/obj.h"
|
||||
#include "py/runtime.h"
|
||||
#include "py/mperrno.h"
|
||||
#include "rng.h"
|
||||
|
||||
#if MICROPY_HW_ENABLE_RNG
|
||||
#error "this code replaces normal RNG module"
|
||||
#endif
|
||||
|
||||
void random_buffer(uint8_t *p, size_t count);
|
||||
|
||||
static void rng_init(void) {
|
||||
if (!(RNG->CR & RNG_CR_RNGEN)) {
|
||||
__HAL_RCC_RNG_CLK_ENABLE();
|
||||
|
||||
RNG->CR |= RNG_CR_RNGEN;
|
||||
|
||||
// TODO: throw out some samples?
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#define RNG_TIMEOUT_MS (10)
|
||||
|
||||
static uint32_t last_value;
|
||||
|
||||
static uint32_t rng_get_or_fault(void)
|
||||
{
|
||||
// Enable the RNG peripheral if it's not already enabled
|
||||
rng_init();
|
||||
|
||||
// Wait for a new random number to be ready, takes on the order of 10us
|
||||
uint32_t start = HAL_GetTick();
|
||||
|
||||
while (!(RNG->SR & RNG_SR_DRDY)) {
|
||||
if (HAL_GetTick() - start >= RNG_TIMEOUT_MS) {
|
||||
// hardware failure... do not return anything!
|
||||
mp_raise_OSError(MP_EFAULT);
|
||||
}
|
||||
}
|
||||
|
||||
// Get and return the new random number
|
||||
last_value = RNG->DR;
|
||||
|
||||
return last_value;
|
||||
}
|
||||
|
||||
/// \function pyb_rng_get()
|
||||
//
|
||||
/// Return a 30-bit hardware generated random number: or fail!
|
||||
//
|
||||
STATIC mp_obj_t pyb_rng_get(void)
|
||||
{
|
||||
// Get and return the new random number
|
||||
return mp_obj_new_int(rng_get_or_fault() >> 2);
|
||||
}
|
||||
|
||||
/// \function rng_get_bytes()
|
||||
/// Fill a buffer with random bits; caller must provide sized buffer.
|
||||
STATIC mp_obj_t pyb_rng_get_bytes(mp_obj_t buffer_io) {
|
||||
|
||||
mp_buffer_info_t bufinfo;
|
||||
mp_get_buffer_raise(buffer_io, &bufinfo, MP_BUFFER_WRITE);
|
||||
|
||||
mp_uint_t count = bufinfo.len;
|
||||
if(count < 1) {
|
||||
mp_raise_ValueError(NULL);
|
||||
}
|
||||
|
||||
// Read 32-bit words and unpack into provided buffer
|
||||
random_buffer(bufinfo.buf, count);
|
||||
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
MP_DEFINE_CONST_FUN_OBJ_0(pyb_rng_get_obj, pyb_rng_get);
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(pyb_rng_get_bytes_obj, pyb_rng_get_bytes);
|
||||
|
||||
|
||||
// compat/replacement for trezor-crypto/rand.[ch]
|
||||
|
||||
// random32()
|
||||
//
|
||||
uint32_t
|
||||
random32(void)
|
||||
{
|
||||
uint32_t rv;
|
||||
|
||||
random_buffer((uint8_t *)&rv, sizeof(uint32_t));
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
// random_buffer()
|
||||
//
|
||||
void
|
||||
random_buffer(uint8_t *p, size_t count)
|
||||
{
|
||||
uint32_t last = last_value;
|
||||
|
||||
while(count) {
|
||||
uint32_t next = rng_get_or_fault();
|
||||
|
||||
if(next == last) {
|
||||
// if rng_init0 isn't called at boot time, then this fault will happen! Very Bad!
|
||||
mp_raise_OSError(MP_EEXIST);
|
||||
}
|
||||
|
||||
int here = MIN(4, count);
|
||||
|
||||
memcpy(p, &next, here);
|
||||
p += here;
|
||||
count -= here;
|
||||
|
||||
last = next;
|
||||
}
|
||||
}
|
||||
|
||||
8
stm32/COLDCARD_Q1/rng.h
Normal file
8
stm32/COLDCARD_Q1/rng.h
Normal file
@ -0,0 +1,8 @@
|
||||
/*
|
||||
* (c) Copyright 2018 by Coinkite Inc. This file is covered by license found in COPYING-CC.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
MP_DECLARE_CONST_FUN_OBJ_0(pyb_rng_get_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_1(pyb_rng_get_bytes_obj);
|
||||
|
||||
116
stm32/COLDCARD_Q1/stm32l4s5_af.csv
Normal file
116
stm32/COLDCARD_Q1/stm32l4s5_af.csv
Normal file
@ -0,0 +1,116 @@
|
||||
Port,,AF0,AF1,AF2,AF3,AF4,AF5,AF6,AF7,AF8,AF9,AF10,AF11,AF12,AF13,AF14,AF15,,
|
||||
,,SYS_AF,TIM1/TIM2/TIM5/TIM8/LPTIM1,TIM1/TIM2/TIM3/TIM4/TIM5,TIM8,I2C1/I2C2/I2C3,SPI1/SPI2,SPI3/DFSDM,USART1/USART2/USART3,UART4/UART5/LPUART1,CAN1/TSC,OTG_FS/QUADSPI,LCD,SDMMC1/COMP1/COMP2/FMC/SWPMI1,SAI1/SAI2,TIM2/TIM15/TIM16/TIM17/LPTIM2,EVENTOUT,ADC,COMP
|
||||
PortA,PA0,,TIM2_CH1,TIM5_CH1,TIM8_ETR,,,,USART2_CTS,UART4_TX,,,,,SAI1_EXTCLK,TIM2_ETR,EVENTOUT,ADC12_IN5,
|
||||
PortA,PA1,,TIM2_CH2,TIM5_CH2,,,,,USART2_RTS/USART2_DE,UART4_RX,,,LCD_SEG0,,,TIM15_CH1N,EVENTOUT,ADC12_IN6,
|
||||
PortA,PA2,,TIM2_CH3,TIM5_CH3,,,,,USART2_TX,,,,LCD_SEG1,,SAI2_EXTCLK,TIM15_CH1,EVENTOUT,ADC12_IN7,
|
||||
PortA,PA3,,TIM2_CH4,TIM5_CH4,,,,,USART2_RX,,,,LCD_SEG2,,,TIM15_CH2,EVENTOUT,ADC12_IN8,
|
||||
PortA,PA4,,,,,,SPI1_NSS,SPI3_NSS,USART2_CK,,,,,,SAI1_FS_B,LPTIM2_OUT,EVENTOUT,ADC12_IN9,
|
||||
PortA,PA5,,TIM2_CH1,TIM2_ETR,TIM8_CH1N,,SPI1_SCK,,,,,,,,,LPTIM2_ETR,EVENTOUT,ADC12_IN10,
|
||||
PortA,PA6,,TIM1_BKIN,TIM3_CH1,TIM8_BKIN,,SPI1_MISO,,USART3_CTS,,,QUADSPI_BK1_IO3,LCD_SEG3,TIM1_BKIN_COMP2,TIM8_BKIN_COMP2,TIM16_CH1,EVENTOUT,ADC12_IN11,
|
||||
PortA,PA7,,TIM1_CH1N,TIM3_CH2,TIM8_CH1N,,SPI1_MOSI,,,,,QUADSPI_BK1_IO2,LCD_SEG4,,,TIM17_CH1,EVENTOUT,ADC12_IN12,
|
||||
PortA,PA8,MCO,TIM1_CH1,,,,,,USART1_CK,,,OTG_FS_SOF,LCD_COM0,,,LPTIM2_OUT,EVENTOUT,,
|
||||
PortA,PA9,,TIM1_CH2,,,,,,USART1_TX,,,,LCD_COM1,,,TIM15_BKIN,EVENTOUT,,
|
||||
PortA,PA10,,TIM1_CH3,,,,,,USART1_RX,,,OTG_FS_ID,LCD_COM2,,,TIM17_BKIN,EVENTOUT,,
|
||||
PortA,PA11,,TIM1_CH4,TIM1_BKIN2,,,,,USART1_CTS,,CAN1_RX,OTG_FS_DM,,TIM1_BKIN2_COMP1,,,EVENTOUT,,
|
||||
PortA,PA12,,TIM1_ETR,,,,,,USART1_RTS/USART1_DE,,CAN1_TX,OTG_FS_DP,,,,,EVENTOUT,,
|
||||
PortA,PA13,JTMS/SWDIO,IR_OUT,,,,,,,,,OTG_FS_NOE,,,,,EVENTOUT,,
|
||||
PortA,PA14,JTCK/SWCLK,,,,,,,,,,,,,,,EVENTOUT,,
|
||||
PortA,PA15,JTDI,TIM2_CH1,TIM2_ETR,,,SPI1_NSS,SPI3_NSS,,UART4_RTS/UART4_DE,TSC_G3_IO1,,LCD_SEG17,,SAI2_FS_B,,EVENTOUT,,
|
||||
PortB,PB0,,TIM1_CH2N,TIM3_CH3,TIM8_CH2N,,,,USART3_CK,,,QUADSPI_BK1_IO1,LCD_SEG5,COMP1_OUT,,,EVENTOUT,ADC12_IN15,
|
||||
PortB,PB1,,TIM1_CH3N,TIM3_CH4,TIM8_CH3N,,,DFSDM_DATIN0,USART3_RTS/USART3_DE,,,QUADSPI_BK1_IO0,LCD_SEG6,,,LPTIM2_IN1,EVENTOUT,ADC12_IN16,COMP1_INN
|
||||
PortB,PB2,RTC_OUT,LPTIM1_OUT,,,I2C3_SMBA,,DFSDM_CKIN0,,,,,,,,,EVENTOUT,,COMP1_INP
|
||||
PortB,PB3,JTDO/TRACESWO,TIM2_CH2,,,,SPI1_SCK,SPI3_SCK,USART1_RTS/USART1_DE,,,,LCD_SEG7,,SAI1_SCK_B,,EVENTOUT,,COMP2_INM
|
||||
PortB,PB4,NJTRST,,TIM3_CH1,,,SPI1_MISO,SPI3_MISO,USART1_CTS,UART5_RTS/UART5_DE,TSC_G2_IO1,,LCD_SEG8,,SAI1_MCLK_B,TIM17_BKIN,EVENTOUT,,COMP2_INP
|
||||
PortB,PB5,,LPTIM1_IN1,TIM3_CH2,,I2C1_SMBA,SPI1_MOSI,SPI3_MOSI,USART1_CK,UART5_CTS,TSC_G2_IO2,,LCD_SEG9,COMP2_OUT,SAI1_SD_B,TIM16_BKIN,EVENTOUT,,
|
||||
PortB,PB6,,LPTIM1_ETR,TIM4_CH1,TIM8_BKIN2,I2C1_SCL,,DFSDM_DATIN5,USART1_TX,,TSC_G2_IO3,,,TIM8_BKIN2_COMP2,SAI1_FS_B,TIM16_CH1N,EVENTOUT,,COMP2_INP
|
||||
PortB,PB7,,LPTIM1_IN2,TIM4_CH2,TIM8_BKIN,I2C1_SDA,,DFSDM_CKIN5,USART1_RX,UART4_CTS,TSC_G2_IO4,,LCD_SEG21,FMC_NL,TIM8_BKIN_COMP1,TIM17_CH1N,EVENTOUT,,COMP2_INM
|
||||
PortB,PB8,,,TIM4_CH3,,I2C1_SCL,,DFSDM_DATIN6,,,CAN1_RX,,LCD_SEG16,SDMMC1_D4,SAI1_MCLK_A,TIM16_CH1,EVENTOUT,,
|
||||
PortB,PB9,,IR_OUT,TIM4_CH4,,I2C1_SDA,SPI2_NSS,DFSDM_CKIN6,,,CAN1_TX,,LCD_COM3,SDMMC1_D5,SAI1_FS_A,TIM17_CH1,EVENTOUT,,
|
||||
PortB,PB10,,TIM2_CH3,,,I2C2_SCL,SPI2_SCK,DFSDM_DATIN7,USART3_TX,LPUART1_RX,,QUADSPI_CLK,LCD_SEG10,COMP1_OUT,SAI1_SCK_A,,EVENTOUT,,
|
||||
PortB,PB11,,TIM2_CH4,,,I2C2_SDA,,DFSDM_CKIN7,USART3_RX,LPUART1_TX,,QUADSPI_NCS,LCD_SEG11,COMP2_OUT,,,EVENTOUT,,
|
||||
PortB,PB12,,TIM1_BKIN,,TIM1_BKIN_COMP2,I2C2_SMBA,SPI2_NSS,DFSDM_DATIN1,USART3_CK,LPUART1_RTS/LPUART1_DE,TSC_G1_IO1,,LCD_SEG12,SWPMI1_IO,SAI2_FS_A,TIM15_BKIN,EVENTOUT,,
|
||||
PortB,PB13,,TIM1_CH1N,,,I2C2_SCL,SPI2_SCK,DFSDM_CKIN1,USART3_CTS,LPUART1_CTS,TSC_G1_IO2,,LCD_SEG13,SWPMI1_TX,SAI2_SCK_A,TIM15_CH1N,EVENTOUT,,
|
||||
PortB,PB14,,TIM1_CH2N,,TIM8_CH2N,I2C2_SDA,SPI2_MISO,DFSDM_DATIN2,USART3_RTS_DE,,TSC_G1_IO3,,LCD_SEG14,SWPMI1_RX,SAI2_MCLK_A,TIM15_CH1,EVENTOUT,,
|
||||
PortB,PB15,RTC_REFIN,TIM1_CH3N,,TIM8_CH3N,,SPI2_MOSI,DFSDM_CKIN2,,,TSC_G1_IO4,,LCD_SEG15,SWPMI1_SUSPEND,SAI2_SD_A,TIM15_CH2,EVENTOUT,,
|
||||
PortC,PC0,,LPTIM1_IN1,,,I2C3_SCL,,DFSDM_DATIN4,,LPUART1_RX,,,LCD_SEG18,,,LPTIM2_IN1,EVENTOUT,ADC123_IN1,
|
||||
PortC,PC1,,LPTIM1_OUT,,,I2C3_SDA,,DFSDM_CKIN4,,LPUART1_TX,,,LCD_SEG19,,,,EVENTOUT,ADC123_IN2,
|
||||
PortC,PC2,,LPTIM1_IN2,,,,SPI2_MISO,DFSDM_CKOUT,,,,,LCD_SEG20,,,,EVENTOUT,ADC123_IN3,
|
||||
PortC,PC3,,LPTIM1_ETR,,,,SPI2_MOSI,,,,,,LCD_VLCD,,SAI1_SD_A,LPTIM2_ETR,EVENTOUT,ADC123_IN4,
|
||||
PortC,PC4,,,,,,,,USART3_TX,,,,LCD_SEG22,,,,EVENTOUT,ADC12_IN13,COMP1_INM
|
||||
PortC,PC5,,,,,,,,USART3_RX,,,,LCD_SEG23,,,,EVENTOUT,ADC12_IN14,COMP1_INP
|
||||
PortC,PC6,,,TIM3_CH1,TIM8_CH1,,,DFSDM_CKIN3,,,TSC_G4_IO1,,LCD_SEG24,SDMMC1_D6,SAI2_MCLK_A,,EVENTOUT,,
|
||||
PortC,PC7,,,TIM3_CH2,TIM8_CH2,,,DFSDM_DATIN3,,,TSC_G4_IO2,,LCD_SEG25,SDMMC1_D7,SAI2_MCLK_B,,EVENTOUT,,
|
||||
PortC,PC8,,,TIM3_CH3,TIM8_CH3,,,,,,TSC_G4_IO3,,LCD_SEG26,SDMMC1_D0,,,EVENTOUT,,
|
||||
PortC,PC9,,TIM8_BKIN2,TIM3_CH4,TIM8_CH4,,,,,,TSC_G4_IO4,OTG_FS_NOE,LCD_SEG27,SDMMC1_D1,SAI2_EXTCLK,TIM8_BKIN2_COMP1,EVENTOUT,,
|
||||
PortC,PC10,,,,,,,SPI3_SCK,USART3_TX,UART4_TX,TSC_G3_IO2,,LCD_COM4/LCD_SEG28/LCD_SEG40,SDMMC1_D2,SAI2_SCK_B,,EVENTOUT,,
|
||||
PortC,PC11,,,,,,,SPI3_MISO,USART3_RX,UART4_RX,TSC_G3_IO3,,LCD_COM5/LCD_SEG29/LCD_SEG41,SDMMC1_D3,SAI2_MCLK_B,,EVENTOUT,,
|
||||
PortC,PC12,,,,,,,SPI3_MOSI,USART3_CK,UART5_TX,TSC_G3_IO4,,LCD_COM6/LCD_SEG30/LCD_SEG42,SDMMC1_CK,SAI2_SD_B,,EVENTOUT,,
|
||||
PortC,PC13,,,,,,,,,,,,,,,,EVENTOUT,,
|
||||
PortC,PC14,,,,,,,,,,,,,,,,EVENTOUT,,
|
||||
PortC,PC15,,,,,,,,,,,,,,,,EVENTOUT,,
|
||||
PortD,PD0,,,,,,SPI2_NSS,DFSDM_DATIN7,,,CAN1_RX,,,FMC_D2,,,EVENTOUT,,
|
||||
PortD,PD1,,,,,,SPI2_SCK,DFSDM_CKIN7,,,CAN1_TX,,,FMC_D3,,,EVENTOUT,,
|
||||
PortD,PD2,,,TIM3_ETR,,,,,USART3_RTS/USART3_DE,UART5_RX,TSC_SYNC,,LCD_COM7/LCD_SEG31/LCD_SEG43,SDMMC1_CMD,,,EVENTOUT,,
|
||||
PortD,PD3,,,,,,SPI2_MISO,DFSDM_DATIN0,USART2_CTS,,,,,FMC_CLK,,,EVENTOUT,,
|
||||
PortD,PD4,,,,,,SPI2_MOSI,DFSDM_CKIN0,USART2_RTS/USART2_DE,,,,,FMC_NOE,,,EVENTOUT,,
|
||||
PortD,PD5,,,,,,,,USART2_TX,,,,,FMC_NWE,,,EVENTOUT,,
|
||||
PortD,PD6,,,,,,,DFSDM_DATIN1,USART2_RX,,,,,FMC_NWAIT,SAI1_SD_A,,EVENTOUT,,
|
||||
PortD,PD7,,,,,,,DFSDM_CKIN1,USART2_CK,,,,,FMC_NE1,,,EVENTOUT,,
|
||||
PortD,PD8,,,,,,,,USART3_TX,,,,LCD_SEG28,FMC_D13,,,EVENTOUT,,
|
||||
PortD,PD9,,,,,,,,USART3_RX,,,,LCD_SEG29,FMC_D14,SAI2_MCLK_A,,EVENTOUT,,
|
||||
PortD,PD10,,,,,,,,USART3_CK,,TSC_G6_IO1,,LCD_SEG30,FMC_D15,SAI2_SCK_A,,EVENTOUT,,
|
||||
PortD,PD11,,,,,,,,USART3_CTS,,TSC_G6_IO2,,LCD_SEG31,FMC_A16,SAI2_SD_A,LPTIM2_ETR,EVENTOUT,,
|
||||
PortD,PD12,,,TIM4_CH1,,,,,USART3_RTS/USART3_DE,,TSC_G6_IO3,,LCD_SEG32,FMC_A17,SAI2_FS_A,LPTIM2_IN1,EVENTOUT,,
|
||||
PortD,PD13,,,TIM4_CH2,,,,,,,TSC_G6_IO4,,LCD_SEG33,FMC_A18,,LPTIM2_OUT,EVENTOUT,,
|
||||
PortD,PD14,,,TIM4_CH3,,,,,,,,,LCD_SEG34,FMC_D0,,,EVENTOUT,,
|
||||
PortD,PD15,,,TIM4_CH4,,,,,,,,,LCD_SEG35,FMC_D1,,,EVENTOUT,,
|
||||
PortE,PE0,,,TIM4_ETR,,,,,,,,,LCD_SEG36,FMC_NBL0,,TIM16_CH1,EVENTOUT,,
|
||||
PortE,PE1,,,,,,,,,,,,LCD_SEG37,FMC_NBL1,,TIM17_CH1,EVENTOUT,,
|
||||
PortE,PE2,TRACECLK,,TIM3_ETR,,,,,,,TSC_G7_IO1,,LCD_SEG38,FMC_A23,SAI1_MCLK_A,,EVENTOUT,,
|
||||
PortE,PE3,TRACED0,,TIM3_CH1,,,,,,,TSC_G7_IO2,,LCD_SEG39,FMC_A19,SAI1_SD_B,,EVENTOUT,,
|
||||
PortE,PE4,TRACED1,,TIM3_CH2,,,,DFSDM_DATIN3,,,TSC_G7_IO3,,,FMC_A20,SAI1_FS_A,,EVENTOUT,,
|
||||
PortE,PE5,TRACED2,,TIM3_CH3,,,,DFSDM_CKIN3,,,TSC_G7_IO4,,,FMC_A21,SAI1_SCK_A,,EVENTOUT,,
|
||||
PortE,PE6,TRACED3,,TIM3_CH4,,,,,,,,,,FMC_A22,SAI1_SD_A,,EVENTOUT,,
|
||||
PortE,PE7,,TIM1_ETR,,,,,DFSDM_DATIN2,,,,,,FMC_D4,SAI1_SD_B,,EVENTOUT,,
|
||||
PortE,PE8,,TIM1_CH1N,,,,,DFSDM_CKIN2,,,,,,FMC_D5,SAI1_SCK_B,,EVENTOUT,,
|
||||
PortE,PE9,,TIM1_CH1,,,,,DFSDM_CKOUT,,,,,,FMC_D6,SAI1_FS_B,,EVENTOUT,,
|
||||
PortE,PE10,,TIM1_CH2N,,,,,DFSDM_DATIN4,,,TSC_G5_IO1,QUADSPI_CLK,,FMC_D7,SAI1_MCLK_B,,EVENTOUT,,
|
||||
PortE,PE11,,TIM1_CH2,,,,,DFSDM_CKIN4,,,TSC_G5_IO2,QUADSPI_NCS,,FMC_D8,,,EVENTOUT,,
|
||||
PortE,PE12,,TIM1_CH3N,,,,SPI1_NSS,DFSDM_DATIN5,,,TSC_G5_IO3,QUADSPI_BK1_IO0,,FMC_D9,,,EVENTOUT,,
|
||||
PortE,PE13,,TIM1_CH3,,,,SPI1_SCK,DFSDM_CKIN5,,,TSC_G5_IO4,QUADSPI_BK1_IO1,,FMC_D10,,,EVENTOUT,,
|
||||
PortE,PE14,,TIM1_CH4,TIM1_BKIN2,TIM1_BKIN2_COMP2,,SPI1_MISO,,,,,QUADSPI_BK1_IO2,,FMC_D11,,,EVENTOUT,,
|
||||
PortE,PE15,,TIM1_BKIN,,TIM1_BKIN_COMP1,,SPI1_MOSI,,,,,QUADSPI_BK1_IO3,,FMC_D12,,,EVENTOUT,,
|
||||
PortF,PF0,,,,,I2C2_SDA,,,,,,,,FMC_A0,,,EVENTOUT,,
|
||||
PortF,PF1,,,,,I2C2_SCL,,,,,,,,FMC_A1,,,EVENTOUT,,
|
||||
PortF,PF2,,,,,I2C2_SMBA,,,,,,,,FMC_A2,,,EVENTOUT,,
|
||||
PortF,PF3,,,,,,,,,,,,,FMC_A3,,,EVENTOUT,ADC3_IN6,
|
||||
PortF,PF4,,,,,,,,,,,,,FMC_A4,,,EVENTOUT,ADC3_IN7,
|
||||
PortF,PF5,,,,,,,,,,,,,FMC_A5,,,EVENTOUT,ADC3_IN8,
|
||||
PortF,PF6,,TIM5_ETR,TIM5_CH1,,,,,,,,,,,SAI1_SD_B,,EVENTOUT,ADC3_IN9,
|
||||
PortF,PF7,,,TIM5_CH2,,,,,,,,,,,SAI1_MCLK_B,,EVENTOUT,ADC3_IN10,
|
||||
PortF,PF8,,,TIM5_CH3,,,,,,,,,,,SAI1_SCK_B,,EVENTOUT,ADC3_IN11,
|
||||
PortF,PF9,,,TIM5_CH4,,,,,,,,,,,SAI1_FS_B,TIM15_CH1,EVENTOUT,ADC3_IN12,
|
||||
PortF,PF10,,,,,,,,,,,,,,,TIM15_CH2,EVENTOUT,ADC3_IN13,
|
||||
PortF,PF11,,,,,,,,,,,,,,,,EVENTOUT,,
|
||||
PortF,PF12,,,,,,,,,,,,,FMC_A6,,,EVENTOUT,,
|
||||
PortF,PF13,,,,,,,DFSDM_DATIN6,,,,,,FMC_A7,,,EVENTOUT,,
|
||||
PortF,PF14,,,,,,,DFSDM_CKIN6,,,TSC_G8_IO1,,,FMC_A8,,,EVENTOUT,,
|
||||
PortF,PF15,,,,,,,,,,TSC_G8_IO2,,,FMC_A9,,,EVENTOUT,,
|
||||
PortG,PG0,,,,,,,,,,TSC_G8_IO3,,,FMC_A10,,,EVENTOUT,,
|
||||
PortG,PG1,,,,,,,,,,TSC_G8_IO4,,,FMC_A11,,,EVENTOUT,,
|
||||
PortG,PG2,,,,,,SPI1_SCK,,,,,,,FMC_A12,SAI2_SCK_B,,EVENTOUT,,
|
||||
PortG,PG3,,,,,,SPI1_MISO,,,,,,,FMC_A13,SAI2_FS_B,,EVENTOUT,,
|
||||
PortG,PG4,,,,,,SPI1_MOSI,,,,,,,FMC_A14,SAI2_MCLK_B,,EVENTOUT,,
|
||||
PortG,PG5,,,,,,SPI1_NSS,,,LPUART1_CTS,,,,FMC_A15,SAI2_SD_B,,EVENTOUT,,
|
||||
PortG,PG6,,,,,I2C3_SMBA,,,,LPUART1_RTS/LPUART1_DE,,,,,,,EVENTOUT,,
|
||||
PortG,PG7,,,,,I2C3_SCL,,,,LPUART1_TX,,,,FMC_INT3,,,EVENTOUT,,
|
||||
PortG,PG8,,,,,I2C3_SDA,,,,LPUART1_RX,,,,,,,EVENTOUT,,
|
||||
PortG,PG9,,,,,,,SPI3_SCK,USART1_TX,,,,,FMC_NCE3/FMC_NE2,SAI2_SCK_A,TIM15_CH1N,EVENTOUT,,
|
||||
PortG,PG10,,LPTIM1_IN1,,,,,SPI3_MISO,USART1_RX,,,,,FMC_NE3,SAI2_FS_A,TIM15_CH1,EVENTOUT,,
|
||||
PortG,PG11,,LPTIM1_IN2,,,,,SPI3_MOSI,USART1_CTS,,,,,,SAI2_MCLK_A,TIM15_CH2,EVENTOUT,,
|
||||
PortG,PG12,,LPTIM1_ETR,,,,,SPI3_NSS,USART1_RTS/USART1_DE,,,,,FMC_NE4,SAI2_SD_A,,EVENTOUT,,
|
||||
PortG,PG13,,,,,I2C1_SDA,,,USART1_CK,,,,,FMC_A24,,,EVENTOUT,,
|
||||
PortG,PG14,,,,,I2C1_SCL,,,,,,,,FMC_A25,,,EVENTOUT,,
|
||||
PortG,PG15,,LPTIM1_OUT,,,I2C1_SMBA,,,,,,,,,,,EVENTOUT,,
|
||||
PortH,PH0,,,,,,,,,,,,,,,,EVENTOUT,,
|
||||
PortH,PH1,,,,,,,,,,,,,,,,EVENTOUT,,
|
||||
|
20
stm32/COLDCARD_Q1/stm32l4xx_hal_conf.h
Normal file
20
stm32/COLDCARD_Q1/stm32l4xx_hal_conf.h
Normal file
@ -0,0 +1,20 @@
|
||||
/* This file is part of the MicroPython project, http://micropython.org/
|
||||
* The MIT License (MIT)
|
||||
* Copyright (c) 2019 Damien P. George
|
||||
*/
|
||||
#ifndef MICROPY_INCLUDED_STM32L4XX_HAL_CONF_H
|
||||
#define MICROPY_INCLUDED_STM32L4XX_HAL_CONF_H
|
||||
|
||||
#include "boards/stm32l4xx_hal_conf_base.h"
|
||||
|
||||
// Oscillator values in Hz
|
||||
#define HSE_VALUE (8000000)
|
||||
#define LSE_VALUE (32768)
|
||||
#define EXTERNAL_SAI1_CLOCK_VALUE (48000)
|
||||
#define EXTERNAL_SAI2_CLOCK_VALUE (48000)
|
||||
|
||||
// Oscillator timeouts in ms
|
||||
#define HSE_STARTUP_TIMEOUT (100)
|
||||
#define LSE_STARTUP_TIMEOUT (5000)
|
||||
|
||||
#endif // MICROPY_INCLUDED_STM32L4XX_HAL_CONF_H
|
||||
1
stm32/COLDCARD_Q1/stm32l4xx_hal_tsc.
Symbolic link
1
stm32/COLDCARD_Q1/stm32l4xx_hal_tsc.
Symbolic link
@ -0,0 +1 @@
|
||||
../../external/micropython/lib/stm32lib/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_tsc.
|
||||
1127
stm32/COLDCARD_Q1/stm32l4xx_hal_tsc.c
Normal file
1127
stm32/COLDCARD_Q1/stm32l4xx_hal_tsc.c
Normal file
File diff suppressed because it is too large
Load Diff
58
stm32/COLDCARD_Q1/ulight.c
Normal file
58
stm32/COLDCARD_Q1/ulight.c
Normal file
@ -0,0 +1,58 @@
|
||||
//
|
||||
// (c) Copyright 2021 by Coinkite Inc. This file is covered by license found in COPYING-CC.
|
||||
//
|
||||
// ulight.c - handle a flashing USB activity light on Mk4 rev B and later.
|
||||
//
|
||||
#include "py/mphal.h"
|
||||
#include "softtimer.h"
|
||||
#include "ulight.h"
|
||||
|
||||
// set this whenever something happens over USB; makes the light flash
|
||||
bool ckcc_usb_active;
|
||||
|
||||
// period for blinking (ms)
|
||||
#define BLINK_RATE 150
|
||||
|
||||
static soft_timer_entry_t led_blinktimer;
|
||||
|
||||
STATIC mp_obj_t led_blinker(mp_obj_t unused_obj)
|
||||
{
|
||||
// Called at 150 ms rate.
|
||||
|
||||
// if something happened in previous time period, keep flashing.
|
||||
bool active = false;
|
||||
if(ckcc_usb_active) {
|
||||
ckcc_usb_active = false;
|
||||
active = true;
|
||||
}
|
||||
|
||||
static bool led_on;
|
||||
if(!active) {
|
||||
if(led_on) {
|
||||
mp_hal_pin_low(USB_LED_PIN);
|
||||
led_on = false;
|
||||
}
|
||||
} else {
|
||||
led_on = !led_on;
|
||||
mp_hal_pin_write(USB_LED_PIN, led_on);
|
||||
}
|
||||
|
||||
return mp_const_none;
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(led_blinker_obj, led_blinker);
|
||||
|
||||
// ulight_setup()
|
||||
//
|
||||
void
|
||||
ulight_setup(void)
|
||||
{
|
||||
// setup USB activity light
|
||||
led_blinktimer.mode = SOFT_TIMER_MODE_PERIODIC;
|
||||
led_blinktimer.delta_ms = BLINK_RATE;
|
||||
led_blinktimer.callback = (void *)&led_blinker_obj;
|
||||
led_blinktimer.pairheap.base.type = MP_ROM_NONE; // not needed
|
||||
|
||||
soft_timer_insert(&led_blinktimer);
|
||||
}
|
||||
|
||||
// EOF
|
||||
19
stm32/COLDCARD_Q1/ulight.h
Normal file
19
stm32/COLDCARD_Q1/ulight.h
Normal file
@ -0,0 +1,19 @@
|
||||
/*
|
||||
* (c) Copyright 2021 by Coinkite Inc. This file is covered by license found in COPYING-CC.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
// active-high LED on this pin
|
||||
#define USB_LED_PIN pin_C6
|
||||
|
||||
// set this whenever something happens over USB; makes the light flash
|
||||
extern bool ckcc_usb_active;
|
||||
|
||||
// call once
|
||||
void ulight_setup(void);
|
||||
|
||||
static inline void ulight_off(void) {
|
||||
mp_hal_pin_low(USB_LED_PIN);
|
||||
}
|
||||
|
||||
// EOF
|
||||
86
stm32/COLDCARD_Q1/vcp_lockdown.c
Normal file
86
stm32/COLDCARD_Q1/vcp_lockdown.c
Normal file
@ -0,0 +1,86 @@
|
||||
/*
|
||||
* (c) Copyright 2018 by Coinkite Inc. This file is covered by license found in COPYING-CC.
|
||||
*/
|
||||
#include <string.h>
|
||||
|
||||
#include "py/runtime.h"
|
||||
#include "py/mperrno.h"
|
||||
#include "py/mphal.h"
|
||||
#include "extmod/misc.h"
|
||||
#include "usb.h"
|
||||
#include "uart.h"
|
||||
#include "lib/utils/interrupt_char.h" // for mp_interrupt_char
|
||||
|
||||
// is the REPL enabled by user (default: no)
|
||||
bool ckcc_vcp_enabled;
|
||||
|
||||
// mp_hal_stdin_rx_chr()
|
||||
//
|
||||
// - replaces code in stm32/mphalport.c
|
||||
// - ignore all keys unless in REPL mode
|
||||
//
|
||||
int
|
||||
mp_hal_stdin_rx_chr(void) {
|
||||
for (;;) {
|
||||
if (MP_STATE_PORT(pyb_stdio_uart) != NULL && uart_rx_any(MP_STATE_PORT(pyb_stdio_uart))) {
|
||||
// consume it, but forward only if enabled.
|
||||
int ch = uart_rx_char(MP_STATE_PORT(pyb_stdio_uart));
|
||||
|
||||
#if COLDCARD_DEBUG
|
||||
return ch;
|
||||
#else
|
||||
if(ckcc_vcp_enabled) return ch;
|
||||
#endif
|
||||
}
|
||||
|
||||
// USB virtual comm port Rx support -- always disabled on Mk4 by design
|
||||
#if 0
|
||||
int dupterm_c = mp_uos_dupterm_rx_chr();
|
||||
if (dupterm_c >= 0) {
|
||||
if(ckcc_vcp_enabled) {
|
||||
return dupterm_c;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
MICROPY_EVENT_POLL_HOOK
|
||||
}
|
||||
}
|
||||
|
||||
// mp_hal_set_interrupt_char()
|
||||
//
|
||||
void
|
||||
mp_hal_set_interrupt_char(int c)
|
||||
{
|
||||
// Replaces content of l-mpy/lib/utils/interrupt_char.c
|
||||
// - many things call this at many times.
|
||||
// - instead, use our ckcc.vcp_enable() call
|
||||
#if COLDCARD_DEBUG
|
||||
mp_interrupt_char = 3;
|
||||
#else
|
||||
mp_interrupt_char = -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
// mp_hal_stdout_tx_strn()
|
||||
//
|
||||
void
|
||||
mp_hal_stdout_tx_strn(const char *str, size_t len)
|
||||
{
|
||||
#if !COLDCARD_DEBUG
|
||||
if(!ckcc_vcp_enabled) {
|
||||
// allow the copyright notice and version string, then no more output
|
||||
static int so_far = 0;
|
||||
|
||||
if(so_far > 84) return;
|
||||
so_far += len;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (MP_STATE_PORT(pyb_stdio_uart) != NULL) {
|
||||
uart_tx_strn(MP_STATE_PORT(pyb_stdio_uart), str, len);
|
||||
}
|
||||
mp_uos_dupterm_tx_strn(str, len);
|
||||
}
|
||||
|
||||
// EOF
|
||||
Loading…
Reference in New Issue
Block a user