pull basics from mk4

This commit is contained in:
Peter D. Gray 2023-01-10 14:33:39 -05:00 committed by scgbckbone
parent 21e84b84ef
commit 2f2a56bd12
20 changed files with 3252 additions and 0 deletions

1
stm32/COLDCARD_Q1/c-modules Symbolic link
View File

@ -0,0 +1 @@
../../external/c-modules

View 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)

View 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

View 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

View 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
View 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

View 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

View 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

View 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)

View 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
1 D0 PA3
2 D1 PA2
3 D2 PA10
4 D3 PB3
5 D4 PB5
6 D5 PB4
7 D6 PB10
8 D7 PA8
9 D8 PA9
10 D9 PC7
11 D10 PB6
12 D11 PA7
13 D12 PA6
14 D13 PA5
15 D14 PB9
16 D15 PB8
17 PA0 PA0
18 PA1 PA1
19 PA2 PA2
20 PA3 PA3
21 PA4 PA4
22 PA5 PA5
23 PA6 PA6
24 PA7 PA7
25 PA8 PA8
26 PA9 PA9
27 PA10 PA10
28 PA15 PA15
29 PB0 PB0
30 PB1 PB1
31 PB2 PB2
32 PB3 PB3
33 PB4 PB4
34 PB5 PB5
35 PB6 PB6
36 PB7 PB7
37 PB8 PB8
38 PB9 PB9
39 PB10 PB10
40 PB11 PB11
41 PB12 PB12
42 PB13 PB13
43 PB14 PB14
44 PB15 PB15
45 PC0 PC0
46 PC1 PC1
47 PC2 PC2
48 PC3 PC3
49 PC4 PC4
50 PC5 PC5
51 PC6 PC6
52 PC7 PC7
53 PC8 PC8
54 PC9 PC9
55 PC10 PC10
56 PC11 PC11
57 PC12 PC12
58 PC13 PC13
59 PC14 PC14
60 PC15 PC15
61 PD2 PD2
62 PH0 PH0
63 PH1 PH1
64 USB_DM PA11
65 USB_DP PA12
66 SD_D0 PC8
67 SD_D1 PC9
68 SD_D2 PC10
69 SD_D3 PC11
70 SD_CMD PD2
71 SD_CK PC12
72 SD_SW PC13
73 SD PA9
74 M2_COL0 PB0
75 M2_COL1 PB1
76 M2_COL2 PB2
77 M2_ROW0 PD8
78 M2_ROW1 PD9
79 M2_ROW2 PD10
80 M2_ROW3 PD11
81 F_CS PB9
82 SF_SCLK PB10
83 SF_MISO PC2
84 SF_MOSI PC3
85 SD_ACTIVE PC7
86 USB_ACTIVE PC6
87 SE2_SCL PB13
88 SE2_SDA PB14
89 NFC_SCL PB6
90 NFC_SDA PB7
91 NFC_ED PC4

View 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
View 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
View 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);

View 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,,
1 Port AF0 AF1 AF2 AF3 AF4 AF5 AF6 AF7 AF8 AF9 AF10 AF11 AF12 AF13 AF14 AF15
2 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
3 PortA PA0 TIM2_CH1 TIM5_CH1 TIM8_ETR USART2_CTS UART4_TX SAI1_EXTCLK TIM2_ETR EVENTOUT ADC12_IN5
4 PortA PA1 TIM2_CH2 TIM5_CH2 USART2_RTS/USART2_DE UART4_RX LCD_SEG0 TIM15_CH1N EVENTOUT ADC12_IN6
5 PortA PA2 TIM2_CH3 TIM5_CH3 USART2_TX LCD_SEG1 SAI2_EXTCLK TIM15_CH1 EVENTOUT ADC12_IN7
6 PortA PA3 TIM2_CH4 TIM5_CH4 USART2_RX LCD_SEG2 TIM15_CH2 EVENTOUT ADC12_IN8
7 PortA PA4 SPI1_NSS SPI3_NSS USART2_CK SAI1_FS_B LPTIM2_OUT EVENTOUT ADC12_IN9
8 PortA PA5 TIM2_CH1 TIM2_ETR TIM8_CH1N SPI1_SCK LPTIM2_ETR EVENTOUT ADC12_IN10
9 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
10 PortA PA7 TIM1_CH1N TIM3_CH2 TIM8_CH1N SPI1_MOSI QUADSPI_BK1_IO2 LCD_SEG4 TIM17_CH1 EVENTOUT ADC12_IN12
11 PortA PA8 MCO TIM1_CH1 USART1_CK OTG_FS_SOF LCD_COM0 LPTIM2_OUT EVENTOUT
12 PortA PA9 TIM1_CH2 USART1_TX LCD_COM1 TIM15_BKIN EVENTOUT
13 PortA PA10 TIM1_CH3 USART1_RX OTG_FS_ID LCD_COM2 TIM17_BKIN EVENTOUT
14 PortA PA11 TIM1_CH4 TIM1_BKIN2 USART1_CTS CAN1_RX OTG_FS_DM TIM1_BKIN2_COMP1 EVENTOUT
15 PortA PA12 TIM1_ETR USART1_RTS/USART1_DE CAN1_TX OTG_FS_DP EVENTOUT
16 PortA PA13 JTMS/SWDIO IR_OUT OTG_FS_NOE EVENTOUT
17 PortA PA14 JTCK/SWCLK EVENTOUT
18 PortA PA15 JTDI TIM2_CH1 TIM2_ETR SPI1_NSS SPI3_NSS UART4_RTS/UART4_DE TSC_G3_IO1 LCD_SEG17 SAI2_FS_B EVENTOUT
19 PortB PB0 TIM1_CH2N TIM3_CH3 TIM8_CH2N USART3_CK QUADSPI_BK1_IO1 LCD_SEG5 COMP1_OUT EVENTOUT ADC12_IN15
20 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
21 PortB PB2 RTC_OUT LPTIM1_OUT I2C3_SMBA DFSDM_CKIN0 EVENTOUT COMP1_INP
22 PortB PB3 JTDO/TRACESWO TIM2_CH2 SPI1_SCK SPI3_SCK USART1_RTS/USART1_DE LCD_SEG7 SAI1_SCK_B EVENTOUT COMP2_INM
23 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
24 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
25 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
26 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
27 PortB PB8 TIM4_CH3 I2C1_SCL DFSDM_DATIN6 CAN1_RX LCD_SEG16 SDMMC1_D4 SAI1_MCLK_A TIM16_CH1 EVENTOUT
28 PortB PB9 IR_OUT TIM4_CH4 I2C1_SDA SPI2_NSS DFSDM_CKIN6 CAN1_TX LCD_COM3 SDMMC1_D5 SAI1_FS_A TIM17_CH1 EVENTOUT
29 PortB PB10 TIM2_CH3 I2C2_SCL SPI2_SCK DFSDM_DATIN7 USART3_TX LPUART1_RX QUADSPI_CLK LCD_SEG10 COMP1_OUT SAI1_SCK_A EVENTOUT
30 PortB PB11 TIM2_CH4 I2C2_SDA DFSDM_CKIN7 USART3_RX LPUART1_TX QUADSPI_NCS LCD_SEG11 COMP2_OUT EVENTOUT
31 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
32 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
33 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
34 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
35 PortC PC0 LPTIM1_IN1 I2C3_SCL DFSDM_DATIN4 LPUART1_RX LCD_SEG18 LPTIM2_IN1 EVENTOUT ADC123_IN1
36 PortC PC1 LPTIM1_OUT I2C3_SDA DFSDM_CKIN4 LPUART1_TX LCD_SEG19 EVENTOUT ADC123_IN2
37 PortC PC2 LPTIM1_IN2 SPI2_MISO DFSDM_CKOUT LCD_SEG20 EVENTOUT ADC123_IN3
38 PortC PC3 LPTIM1_ETR SPI2_MOSI LCD_VLCD SAI1_SD_A LPTIM2_ETR EVENTOUT ADC123_IN4
39 PortC PC4 USART3_TX LCD_SEG22 EVENTOUT ADC12_IN13 COMP1_INM
40 PortC PC5 USART3_RX LCD_SEG23 EVENTOUT ADC12_IN14 COMP1_INP
41 PortC PC6 TIM3_CH1 TIM8_CH1 DFSDM_CKIN3 TSC_G4_IO1 LCD_SEG24 SDMMC1_D6 SAI2_MCLK_A EVENTOUT
42 PortC PC7 TIM3_CH2 TIM8_CH2 DFSDM_DATIN3 TSC_G4_IO2 LCD_SEG25 SDMMC1_D7 SAI2_MCLK_B EVENTOUT
43 PortC PC8 TIM3_CH3 TIM8_CH3 TSC_G4_IO3 LCD_SEG26 SDMMC1_D0 EVENTOUT
44 PortC PC9 TIM8_BKIN2 TIM3_CH4 TIM8_CH4 TSC_G4_IO4 OTG_FS_NOE LCD_SEG27 SDMMC1_D1 SAI2_EXTCLK TIM8_BKIN2_COMP1 EVENTOUT
45 PortC PC10 SPI3_SCK USART3_TX UART4_TX TSC_G3_IO2 LCD_COM4/LCD_SEG28/LCD_SEG40 SDMMC1_D2 SAI2_SCK_B EVENTOUT
46 PortC PC11 SPI3_MISO USART3_RX UART4_RX TSC_G3_IO3 LCD_COM5/LCD_SEG29/LCD_SEG41 SDMMC1_D3 SAI2_MCLK_B EVENTOUT
47 PortC PC12 SPI3_MOSI USART3_CK UART5_TX TSC_G3_IO4 LCD_COM6/LCD_SEG30/LCD_SEG42 SDMMC1_CK SAI2_SD_B EVENTOUT
48 PortC PC13 EVENTOUT
49 PortC PC14 EVENTOUT
50 PortC PC15 EVENTOUT
51 PortD PD0 SPI2_NSS DFSDM_DATIN7 CAN1_RX FMC_D2 EVENTOUT
52 PortD PD1 SPI2_SCK DFSDM_CKIN7 CAN1_TX FMC_D3 EVENTOUT
53 PortD PD2 TIM3_ETR USART3_RTS/USART3_DE UART5_RX TSC_SYNC LCD_COM7/LCD_SEG31/LCD_SEG43 SDMMC1_CMD EVENTOUT
54 PortD PD3 SPI2_MISO DFSDM_DATIN0 USART2_CTS FMC_CLK EVENTOUT
55 PortD PD4 SPI2_MOSI DFSDM_CKIN0 USART2_RTS/USART2_DE FMC_NOE EVENTOUT
56 PortD PD5 USART2_TX FMC_NWE EVENTOUT
57 PortD PD6 DFSDM_DATIN1 USART2_RX FMC_NWAIT SAI1_SD_A EVENTOUT
58 PortD PD7 DFSDM_CKIN1 USART2_CK FMC_NE1 EVENTOUT
59 PortD PD8 USART3_TX LCD_SEG28 FMC_D13 EVENTOUT
60 PortD PD9 USART3_RX LCD_SEG29 FMC_D14 SAI2_MCLK_A EVENTOUT
61 PortD PD10 USART3_CK TSC_G6_IO1 LCD_SEG30 FMC_D15 SAI2_SCK_A EVENTOUT
62 PortD PD11 USART3_CTS TSC_G6_IO2 LCD_SEG31 FMC_A16 SAI2_SD_A LPTIM2_ETR EVENTOUT
63 PortD PD12 TIM4_CH1 USART3_RTS/USART3_DE TSC_G6_IO3 LCD_SEG32 FMC_A17 SAI2_FS_A LPTIM2_IN1 EVENTOUT
64 PortD PD13 TIM4_CH2 TSC_G6_IO4 LCD_SEG33 FMC_A18 LPTIM2_OUT EVENTOUT
65 PortD PD14 TIM4_CH3 LCD_SEG34 FMC_D0 EVENTOUT
66 PortD PD15 TIM4_CH4 LCD_SEG35 FMC_D1 EVENTOUT
67 PortE PE0 TIM4_ETR LCD_SEG36 FMC_NBL0 TIM16_CH1 EVENTOUT
68 PortE PE1 LCD_SEG37 FMC_NBL1 TIM17_CH1 EVENTOUT
69 PortE PE2 TRACECLK TIM3_ETR TSC_G7_IO1 LCD_SEG38 FMC_A23 SAI1_MCLK_A EVENTOUT
70 PortE PE3 TRACED0 TIM3_CH1 TSC_G7_IO2 LCD_SEG39 FMC_A19 SAI1_SD_B EVENTOUT
71 PortE PE4 TRACED1 TIM3_CH2 DFSDM_DATIN3 TSC_G7_IO3 FMC_A20 SAI1_FS_A EVENTOUT
72 PortE PE5 TRACED2 TIM3_CH3 DFSDM_CKIN3 TSC_G7_IO4 FMC_A21 SAI1_SCK_A EVENTOUT
73 PortE PE6 TRACED3 TIM3_CH4 FMC_A22 SAI1_SD_A EVENTOUT
74 PortE PE7 TIM1_ETR DFSDM_DATIN2 FMC_D4 SAI1_SD_B EVENTOUT
75 PortE PE8 TIM1_CH1N DFSDM_CKIN2 FMC_D5 SAI1_SCK_B EVENTOUT
76 PortE PE9 TIM1_CH1 DFSDM_CKOUT FMC_D6 SAI1_FS_B EVENTOUT
77 PortE PE10 TIM1_CH2N DFSDM_DATIN4 TSC_G5_IO1 QUADSPI_CLK FMC_D7 SAI1_MCLK_B EVENTOUT
78 PortE PE11 TIM1_CH2 DFSDM_CKIN4 TSC_G5_IO2 QUADSPI_NCS FMC_D8 EVENTOUT
79 PortE PE12 TIM1_CH3N SPI1_NSS DFSDM_DATIN5 TSC_G5_IO3 QUADSPI_BK1_IO0 FMC_D9 EVENTOUT
80 PortE PE13 TIM1_CH3 SPI1_SCK DFSDM_CKIN5 TSC_G5_IO4 QUADSPI_BK1_IO1 FMC_D10 EVENTOUT
81 PortE PE14 TIM1_CH4 TIM1_BKIN2 TIM1_BKIN2_COMP2 SPI1_MISO QUADSPI_BK1_IO2 FMC_D11 EVENTOUT
82 PortE PE15 TIM1_BKIN TIM1_BKIN_COMP1 SPI1_MOSI QUADSPI_BK1_IO3 FMC_D12 EVENTOUT
83 PortF PF0 I2C2_SDA FMC_A0 EVENTOUT
84 PortF PF1 I2C2_SCL FMC_A1 EVENTOUT
85 PortF PF2 I2C2_SMBA FMC_A2 EVENTOUT
86 PortF PF3 FMC_A3 EVENTOUT ADC3_IN6
87 PortF PF4 FMC_A4 EVENTOUT ADC3_IN7
88 PortF PF5 FMC_A5 EVENTOUT ADC3_IN8
89 PortF PF6 TIM5_ETR TIM5_CH1 SAI1_SD_B EVENTOUT ADC3_IN9
90 PortF PF7 TIM5_CH2 SAI1_MCLK_B EVENTOUT ADC3_IN10
91 PortF PF8 TIM5_CH3 SAI1_SCK_B EVENTOUT ADC3_IN11
92 PortF PF9 TIM5_CH4 SAI1_FS_B TIM15_CH1 EVENTOUT ADC3_IN12
93 PortF PF10 TIM15_CH2 EVENTOUT ADC3_IN13
94 PortF PF11 EVENTOUT
95 PortF PF12 FMC_A6 EVENTOUT
96 PortF PF13 DFSDM_DATIN6 FMC_A7 EVENTOUT
97 PortF PF14 DFSDM_CKIN6 TSC_G8_IO1 FMC_A8 EVENTOUT
98 PortF PF15 TSC_G8_IO2 FMC_A9 EVENTOUT
99 PortG PG0 TSC_G8_IO3 FMC_A10 EVENTOUT
100 PortG PG1 TSC_G8_IO4 FMC_A11 EVENTOUT
101 PortG PG2 SPI1_SCK FMC_A12 SAI2_SCK_B EVENTOUT
102 PortG PG3 SPI1_MISO FMC_A13 SAI2_FS_B EVENTOUT
103 PortG PG4 SPI1_MOSI FMC_A14 SAI2_MCLK_B EVENTOUT
104 PortG PG5 SPI1_NSS LPUART1_CTS FMC_A15 SAI2_SD_B EVENTOUT
105 PortG PG6 I2C3_SMBA LPUART1_RTS/LPUART1_DE EVENTOUT
106 PortG PG7 I2C3_SCL LPUART1_TX FMC_INT3 EVENTOUT
107 PortG PG8 I2C3_SDA LPUART1_RX EVENTOUT
108 PortG PG9 SPI3_SCK USART1_TX FMC_NCE3/FMC_NE2 SAI2_SCK_A TIM15_CH1N EVENTOUT
109 PortG PG10 LPTIM1_IN1 SPI3_MISO USART1_RX FMC_NE3 SAI2_FS_A TIM15_CH1 EVENTOUT
110 PortG PG11 LPTIM1_IN2 SPI3_MOSI USART1_CTS SAI2_MCLK_A TIM15_CH2 EVENTOUT
111 PortG PG12 LPTIM1_ETR SPI3_NSS USART1_RTS/USART1_DE FMC_NE4 SAI2_SD_A EVENTOUT
112 PortG PG13 I2C1_SDA USART1_CK FMC_A24 EVENTOUT
113 PortG PG14 I2C1_SCL FMC_A25 EVENTOUT
114 PortG PG15 LPTIM1_OUT I2C1_SMBA EVENTOUT
115 PortH PH0 EVENTOUT
116 PortH PH1 EVENTOUT

View 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

View File

@ -0,0 +1 @@
../../external/micropython/lib/stm32lib/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_tsc.

File diff suppressed because it is too large Load Diff

View 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

View 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

View 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