From 8313b61dab467a7d9823e32aca9603f804ff3ca8 Mon Sep 17 00:00:00 2001 From: Rutherther Date: Sun, 8 Dec 2024 14:03:27 +0100 Subject: [PATCH] feat: implement fmc sdram control --- include/fmc.h | 70 ++++++++++++++ src/fmc.c | 192 ++++++++++++++++++++++++++++++++++++++ src/main.c | 253 +++++++++++++++++++++++++++++++++++++++++--------- 3 files changed, 471 insertions(+), 44 deletions(-) create mode 100644 include/fmc.h create mode 100644 src/fmc.c diff --git a/include/fmc.h b/include/fmc.h new file mode 100644 index 0000000..832f0af --- /dev/null +++ b/include/fmc.h @@ -0,0 +1,70 @@ +#include +#include +#include + +#ifndef FMC_H +#define FMC_H + +typedef enum { + SDRAM_BANK1 = 0, + SDRAM_BANK2 = 1, +} sdram_bank_t; + +typedef struct { + uint32_t* base; + uint32_t allocated; +} fmc_sdram_t; + +typedef struct { + FMC_Bank1_TypeDef *bank1; + FMC_Bank2_TypeDef *bank2; + FMC_Bank3_TypeDef *bank3; + FMC_Bank5_6_TypeDef *bank5_6; + + fmc_sdram_t sdram[2]; +} fmc_t; + +typedef struct { + uint8_t startup_delay_us; + uint32_t max_sd_clock_hz; + uint32_t refresh_period_ns; + uint8_t mode_register_to_active; + uint8_t exit_self_refresh; + uint8_t active_to_precharge; + uint8_t row_cycle; + uint8_t row_precharge; + uint8_t row_to_column; +} fmc_sdram_timing_t; + +typedef struct { + uint32_t clock_frequency; + uint8_t column_bits; + uint8_t row_bits; + uint8_t memory_data_width; + uint8_t internal_banks; + uint8_t cas_latency; + bool write_protection; + bool read_burst; + uint8_t read_pipe_delay_cycles; +} fmc_sdram_configuration_t; + +typedef enum { + SDRAM_NORMAL_MODE, + SDRAM_CLK_ENABLE, + SDRAM_PRECHARGE_ALL, + SDRAM_AUTOREFRESH, + SDRAM_LOAD_MODE, + SDRAM_SELFREFRESH, + SDRAM_POWERDOWN, +} fmc_sdram_cmd_type_t; + +void fmc_init(fmc_t* fmc); + +void fmc_sdram_configure(fmc_t *fmc, sdram_bank_t target_bank, + fmc_sdram_configuration_t config, + fmc_sdram_timing_t timing, + uint16_t mode_register); +void fmc_sdram_send_command(fmc_t* fmc, uint16_t bank, fmc_sdram_cmd_type_t cmd, uint16_t argument); +void* fmc_sdram_allocate(fmc_t* fmc, sdram_bank_t bank, uint32_t size); + +#endif // FMC_H diff --git a/src/fmc.c b/src/fmc.c new file mode 100644 index 0000000..3af16cb --- /dev/null +++ b/src/fmc.c @@ -0,0 +1,192 @@ +// NOTE: most of the code here is translated from a Rust crate +// https://github.com/stm32-rs/stm32-fmc + +#include "fmc.h" +#include "registers.h" +#include "stm32h747xx.h" +#include "delay.h" + +void fmc_init(fmc_t *fmc) { + fmc->bank1 = FMC_Bank1_R; + fmc->bank2 = FMC_Bank2_R; + fmc->bank3 = FMC_Bank3_R; + fmc->bank5_6 = FMC_Bank5_6_R; + + fmc->sdram[0].allocated = 0; + fmc->sdram[0].base = (uint32_t*)0xC0000000; + fmc->sdram[1].allocated = 0; + fmc->sdram[1].base = (uint32_t*)0xD0000000; +} + +uint32_t max(uint32_t a, uint32_t b) { + return (a > b) ? a : b; +} + +void fmc_sdram_configure(fmc_t *fmc, sdram_bank_t target_bank, fmc_sdram_configuration_t config, + fmc_sdram_timing_t timing, uint16_t mode_register) { + reg_write_bits(&fmc->bank5_6->SDCR[0], + (config.read_pipe_delay_cycles << FMC_SDCRx_RPIPE_Pos) | + (config.read_burst << FMC_SDCRx_RBURST_Pos) | + (2 << FMC_SDCRx_SDCLK_Pos), + FMC_SDCRx_RPIPE_Msk | FMC_SDCRx_RBURST_Msk | FMC_SDCRx_SDCLK_Msk); + + uint8_t internal_banks; + switch (config.internal_banks) { + case 2: + internal_banks = 0; + break; + case 4: + internal_banks = 1; + break; + default: + // Error! + break; + } + + uint8_t memory_data_width; + switch (config.memory_data_width) { + case 8: + memory_data_width = 0; + break; + case 16: + memory_data_width = 1; + break; + case 32: + memory_data_width = 2; + break; + default: + // Error! + break; + } + + reg_write_bits(&fmc->bank5_6->SDCR[target_bank], + (config.write_protection << FMC_SDCRx_WP_Pos) | + (config.cas_latency << FMC_SDCRx_CAS_Pos) | + (internal_banks << FMC_SDCRx_NB_Pos) | + (memory_data_width << FMC_SDCRx_MWID_Pos) | + ((config.row_bits - 11) << FMC_SDCRx_NR_Pos) | + ((config.column_bits - 8) << FMC_SDCRx_NC_Pos), + FMC_SDCRx_WP_Msk | FMC_SDCRx_CAS_Msk | + FMC_SDCRx_NB_Msk | FMC_SDCRx_MWID_Msk | + FMC_SDCRx_NR_Msk | FMC_SDCRx_NC_Msk); + + // Timing ---- SDTR REGISTER + + // Self refresh >= ACTIVE to PRECHARGE + uint32_t minimum_self_refresh = timing.active_to_precharge; + + // Write recovery - Self refresh + uint32_t write_recovery_self_refresh = + minimum_self_refresh - timing.row_to_column; + // Write recovery - WRITE command to PRECHARGE command + uint32_t write_recovery_row_cycle = + timing.row_cycle - timing.row_to_column - timing.row_precharge; + uint32_t write_recovery = + max(write_recovery_self_refresh, write_recovery_row_cycle); + + reg_write_bits(&fmc->bank5_6->SDTR[0], + ((timing.row_cycle - 1) << FMC_SDTRx_TRC_Pos) | + ((timing.row_precharge - 1) << FMC_SDTRx_TRP_Pos), + FMC_SDTRx_TRC_Msk | FMC_SDTRx_TRP_Msk); + + reg_write_bits(&fmc->bank5_6->SDTR[target_bank], + ((timing.row_to_column - 1)) << FMC_SDTRx_TRCD_Pos | + ((write_recovery - 1)) << FMC_SDTRx_TWR_Pos | + ((minimum_self_refresh - 1)) << FMC_SDTRx_TRAS_Pos | + ((timing.exit_self_refresh - 1)) << FMC_SDTRx_TXSR_Pos | + ((timing.mode_register_to_active - 1)) << FMC_SDTRx_TMRD_Pos, + FMC_SDTRx_TRCD_Msk | FMC_SDTRx_TWR_Msk | + FMC_SDTRx_TRAS_Msk | FMC_SDTRx_TXSR_Msk | + FMC_SDTRx_TMRD_Msk); + + + // TODO: is this right? + reg_set_bits(&fmc->bank1->BTCR[0], FMC_BCR1_FMCEN_Msk); + + fmc_sdram_send_command(fmc, target_bank, SDRAM_CLK_ENABLE, 0); + + DELAY_US(config.startup_delay_us); + + fmc_sdram_send_command(fmc, target_bank, SDRAM_PRECHARGE_ALL, 0); + fmc_sdram_send_command(fmc, target_bank, SDRAM_AUTOREFRESH, 8); + fmc_sdram_send_command(fmc, target_bank, SDRAM_LOAD_MODE, mode_register); + + uint64_t refresh_counter_top = (((uint64_t)timing.refresh_period_ns + * (uint64_t)timing.max_sd_clock_hz) + / 1000000000) - 20; + + reg_write_bits(&fmc->bank5_6->SDRTR, + (refresh_counter_top << FMC_SDRTR_COUNT_Pos), FMC_SDRTR_COUNT_Msk); +} + +void *fmc_sdram_allocate(fmc_t *fmc, sdram_bank_t bank, uint32_t size) { + size = ((size + 3) / 4) * 4; + + uint32_t *data = (fmc->sdram[bank].base + fmc->sdram[bank].allocated); + fmc->sdram[bank].allocated += size; + + return (void*)data; +} + +void fmc_sdram_send_command(fmc_t *fmc, uint16_t bank, fmc_sdram_cmd_type_t cmd, + uint16_t argument) { + + uint32_t cmd_type, number_refresh, mode_reg; + + switch (cmd) { + case SDRAM_NORMAL_MODE: + cmd_type = 0; + number_refresh = 1; + mode_reg = 0; + break; + case SDRAM_CLK_ENABLE: + cmd_type = 1; + number_refresh = 1; + mode_reg = 0; + break; + case SDRAM_PRECHARGE_ALL: + cmd_type = 2; + number_refresh = 1; + mode_reg = 0; + break; + case SDRAM_AUTOREFRESH: + cmd_type = 3; + number_refresh = argument; + mode_reg = 0; + break; + case SDRAM_LOAD_MODE: + cmd_type = 4; + number_refresh = 1; + mode_reg = argument; + break; + case SDRAM_SELFREFRESH: + cmd_type = 5; + number_refresh = 1; + mode_reg = 0; + break; + case SDRAM_POWERDOWN: + cmd_type = 6; + number_refresh = 0; + mode_reg = 0; + break; + } + + uint32_t b1, b2; + switch (bank) { + case 0: + b1 = 1; + b2 = 0; + break; + case 1: + b1 = 0; + b2 = 1; + break; + } + + fmc->bank5_6->SDCMR = + (mode_reg << FMC_SDCMR_MRD_Pos) | + (number_refresh << FMC_SDCMR_NRFS_Pos) | + (b1 << FMC_SDCMR_CTB1_Pos) | + (b2 << FMC_SDCMR_CTB2_Pos) | + (cmd_type << FMC_SDCMR_MODE_Pos); +} diff --git a/src/main.c b/src/main.c index ca93494..e62cfeb 100644 --- a/src/main.c +++ b/src/main.c @@ -9,12 +9,17 @@ #include "exti.h" #include "registers.h" #include "pin.h" +#include "fmc.h" #define LED1_GPIO GPIOI #define LED1_PIN 12 /* #define LED2_PIN 13 */ void hard_fault_handler() { + volatile uint32_t cfsr = SCB->CFSR; + volatile uint32_t hfsr = SCB->HFSR; + volatile uint32_t bfar = SCB->BFAR; + while(1) {} } @@ -43,9 +48,6 @@ void led_input() void led_gpio_en() { RCC->AHB4ENR |= (1 << RCC_AHB4ENR_GPIOIEN_Pos); - volatile uint32_t dummy; - dummy = RCC->AHB4ENR; - dummy = RCC->AHB4ENR; } void exti15_10_handler(void) @@ -58,48 +60,215 @@ void exti15_10_handler(void) void main() { + clocks_wait_ready(CLOCK_HSI); + + // Clock gating + RCC->APB4ENR |= RCC_APB4ENR_SYSCFGEN; + RCC->AHB4ENR |= RCC_AHB4ENR_GPIOAEN | RCC_AHB4ENR_GPIOBEN | + RCC_AHB4ENR_GPIOCEN | RCC_AHB4ENR_GPIODEN | + RCC_AHB4ENR_GPIOEEN | RCC_AHB4ENR_GPIOFEN | + RCC_AHB4ENR_GPIOGEN | RCC_AHB4ENR_GPIOHEN | + RCC_AHB4ENR_GPIOIEN | RCC_AHB4ENR_GPIOJEN; + systick_configure(); // Clocks section // Enable hsi48 for usb - RCC->CR |= RCC_CR_HSI48ON; - while ((RCC->CR & RCC_CR_HSI48RDY) == 0); - - // TODO: pll, system clock switch... too complicated it seems. - // Getting hard faults, apparently because of too low voltage - // Has to be enabled before vco can be changed - /* PWR->CR3 |= PWR_CR3_LDOEN; */ - /* PWR->CR3 &= ~PWR_CR3_LDOEN; */ - /* reg_write_bits_pos(&PWR->D3CR, 2, PWR_D3CR_VOS_Pos, 3); */ - - /* /\* SYSCFG->PWRCR |= SYSCFG_PWRCR_ODEN; *\/ */ - - /* while((PWR->CSR1 & PWR_CSR1_ACTVOSRDY) == 0); */ - /* /\* while((PWR->D3CR & PWR_D3CR_VOSRDY) == 0); *\/ */ - - /* reg_write_bits(&FLASH->ACR, FLASH_ACR_LATENCY_3WS, FLASH_ACR_LATENCY_Msk); */ - - /* // HSI is 64 MHz, not divided */ - /* // Diving by 32 to put to PLL -> 2 MHz */ - /* // DIVN = 360 -> F_VCO = 720 MHz */ - /* // DIVP = 2 -> pll1_p is 360 MHz */ - /* // DIVQ = 8 -> pll1_q is 90 MHz */ - /* // DIVR = 8 -> pll1_r is 90 MHz */ - /* clocks_pll_configure(CLOCK_PLL1, 32, PLL_SOURCE_HSI, */ - /* 360, 2, 8, 8); */ - /* clocks_pll_enable(CLOCK_PLL1); */ - /* clocks_pll_wait_ready(CLOCK_PLL1, 300); */ - /* clocks_system_clock_source(CLOCK_SOURCE_PLL_1_P_CK, */ - /* 1, 1, 2, 300); */ + clocks_enable(CLOCK_HSI48); + clocks_wait_ready(CLOCK_HSI48); - // Clock gating - RCC->APB4ENR |= RCC_APB4ENR_SYSCFGEN; - volatile uint32_t dummy; - dummy = RCC->APB4ENR; - dummy = RCC->APB4ENR; - RCC->AHB4ENR |= RCC_AHB4ENR_GPIOAEN | RCC_AHB4ENR_GPIOBEN | RCC_AHB4ENR_GPIOCEN | RCC_AHB4ENR_GPIOHEN | RCC_AHB4ENR_GPIOIEN | RCC_AHB4ENR_GPIOJEN; - dummy = RCC->AHB4ENR; - dummy = RCC->AHB4ENR; + clocks_enable(CLOCK_HSE); + clocks_wait_ready(CLOCK_HSE); + + // HSE 25 MHz -> divide by 25 -> 1 MHz + // HSE / 25 * 400 = FVCO = 400 MHz + // PLL2 R = 200 MHz + reg_set_bits(&RCC->PLLCFGR, RCC_PLLCFGR_PLL3VCOSEL_Msk); + clocks_pll_configure(CLOCK_PLL2, 25, PLL_SOURCE_HSE, 400, 2, 2, 2); + clocks_pll_enable(CLOCK_PLL2); + clocks_pll_wait_ready(CLOCK_PLL2, 300); + + fmc_t fmc; + // select pll 2 r as fmc clock + reg_write_bits(&RCC->D1CCIPR, 2 << (RCC_D1CCIPR_FMCSEL_Pos), RCC_D1CCIPR_FMCSEL_Msk); + RCC->AHB3ENR |= RCC_AHB3ENR_FMCEN; + fmc_init(&fmc); + + #define BURST_LENGTH_1 0x0000 + #define BURST_TYPE_SEQUENTIAL 0x0000 + #define CAS_LATENCY_3 0x0030 + #define OPERATING_MODE_STANDARD 0x0000 + #define WRITEBURST_MODE_SINGLE 0x0200 + uint16_t sdram_mode_register = BURST_LENGTH_1 | BURST_TYPE_SEQUENTIAL | + CAS_LATENCY_3 | OPERATING_MODE_STANDARD | + WRITEBURST_MODE_SINGLE; + + fmc_sdram_timing_t sdram_timing = { + .startup_delay_us = 100, // 100 µs + .max_sd_clock_hz = 100000000, // 100 MHz + .refresh_period_ns = 15625, // 64ms / (4096 rows) = 15625ns + .mode_register_to_active = 2, // tMRD = 2 cycles + .exit_self_refresh = 7, // tXSR = 70ns + .active_to_precharge = 4, // tRAS = 42ns + .row_cycle = 7, // tRC = 70ns + .row_precharge = 2, // tRP = 18ns + .row_to_column = 2, // tRCD = 18ns + }; + fmc_sdram_configuration_t sdram_config = { + .column_bits = 9, + .row_bits = 12, + .memory_data_width = 32, // 32-bit + .internal_banks = 4, // 4 internal banks + .cas_latency = 3, // CAS latency = 3 + .write_protection = false, + .read_burst = true, + .read_pipe_delay_cycles = 0, + }; + + { + pin_t pin_addr[12]; + pin_t pin_data[32]; + pin_t pin_ba[2]; + pin_t pin_nbl[4]; + pin_t pin_sdcke1; + pin_t pin_sdclk; + pin_t pin_sdncas; + pin_t pin_sdne1; + pin_t pin_sdras; + pin_t pin_sdnwe; + + // A0-A11 + pin_init(&pin_addr[0], GPIOF, 0); + pin_init(&pin_addr[1], GPIOF, 1); + pin_init(&pin_addr[2], GPIOF, 2); + pin_init(&pin_addr[3], GPIOF, 3); + pin_init(&pin_addr[4], GPIOF, 4); + pin_init(&pin_addr[5], GPIOF, 5); + pin_init(&pin_addr[6], GPIOF, 12); + pin_init(&pin_addr[7], GPIOF, 13); + pin_init(&pin_addr[8], GPIOF, 14); + pin_init(&pin_addr[9], GPIOF, 15); + pin_init(&pin_addr[10], GPIOG, 0); + pin_init(&pin_addr[11], GPIOG, 1); + // BA0-BA1 + pin_init(&pin_ba[0], GPIOG, 4); + pin_init(&pin_ba[1], GPIOG, 5); + // D0-D31 + pin_init(&pin_data[0], GPIOD, 14); + pin_init(&pin_data[1], GPIOD, 15); + pin_init(&pin_data[2], GPIOD, 0); + pin_init(&pin_data[3], GPIOD, 1); + pin_init(&pin_data[4], GPIOE, 7); + pin_init(&pin_data[5], GPIOE, 8); + pin_init(&pin_data[6], GPIOE, 9); + pin_init(&pin_data[7], GPIOE, 10); + pin_init(&pin_data[8], GPIOE, 11); + pin_init(&pin_data[9], GPIOE, 12); + pin_init(&pin_data[10], GPIOE, 13); + pin_init(&pin_data[11], GPIOE, 14); + pin_init(&pin_data[12], GPIOE, 15); + pin_init(&pin_data[13], GPIOD, 8); + pin_init(&pin_data[14], GPIOD, 9); + pin_init(&pin_data[15], GPIOD, 10); + pin_init(&pin_data[16], GPIOH, 8); + pin_init(&pin_data[17], GPIOH, 9); + pin_init(&pin_data[18], GPIOH, 10); + pin_init(&pin_data[19], GPIOH, 11); + pin_init(&pin_data[20], GPIOH, 12); + pin_init(&pin_data[21], GPIOH, 13); + pin_init(&pin_data[22], GPIOH, 14); + pin_init(&pin_data[23], GPIOH, 15); + pin_init(&pin_data[24], GPIOI, 0); + pin_init(&pin_data[25], GPIOI, 1); + pin_init(&pin_data[26], GPIOI, 2); + pin_init(&pin_data[27], GPIOI, 3); + pin_init(&pin_data[28], GPIOI, 6); + pin_init(&pin_data[29], GPIOI, 7); + pin_init(&pin_data[30], GPIOI, 9); + pin_init(&pin_data[31], GPIOI, 10); + + pin_init(&pin_nbl[0], GPIOE, 0); + pin_init(&pin_nbl[1], GPIOE, 1); + pin_init(&pin_nbl[2], GPIOI, 4); + pin_init(&pin_nbl[3], GPIOI, 5); + + pin_init(&pin_sdcke1, GPIOH, 7); + pin_init(&pin_sdclk, GPIOG, 8); + pin_init(&pin_sdncas, GPIOG, 15); + pin_init(&pin_sdne1, GPIOH, 6); + pin_init(&pin_sdras, GPIOF, 11); + pin_init(&pin_sdnwe, GPIOH, 5); + + // A0-A11 + pin_into_alternate_highspeed(&pin_addr[0], 12); + pin_into_alternate_highspeed(&pin_addr[1], 12); + pin_into_alternate_highspeed(&pin_addr[2], 12); + pin_into_alternate_highspeed(&pin_addr[3], 12); + pin_into_alternate_highspeed(&pin_addr[4], 12); + pin_into_alternate_highspeed(&pin_addr[5], 12); + pin_into_alternate_highspeed(&pin_addr[6], 12); + pin_into_alternate_highspeed(&pin_addr[7], 12); + pin_into_alternate_highspeed(&pin_addr[8], 12); + pin_into_alternate_highspeed(&pin_addr[9], 12); + pin_into_alternate_highspeed(&pin_addr[10], 12); + pin_into_alternate_highspeed(&pin_addr[11], 12); + // BA0-BA1 + pin_into_alternate_highspeed(&pin_ba[0], 12); + pin_into_alternate_highspeed(&pin_ba[1], 12); + // D0-D31 + pin_into_alternate_highspeed(&pin_data[0], 12); + pin_into_alternate_highspeed(&pin_data[1], 12); + pin_into_alternate_highspeed(&pin_data[2], 12); + pin_into_alternate_highspeed(&pin_data[3], 12); + pin_into_alternate_highspeed(&pin_data[4], 12); + pin_into_alternate_highspeed(&pin_data[5], 12); + pin_into_alternate_highspeed(&pin_data[6], 12); + pin_into_alternate_highspeed(&pin_data[7], 12); + pin_into_alternate_highspeed(&pin_data[8], 12); + pin_into_alternate_highspeed(&pin_data[9], 12); + pin_into_alternate_highspeed(&pin_data[10], 12); + pin_into_alternate_highspeed(&pin_data[11], 12); + pin_into_alternate_highspeed(&pin_data[12], 12); + pin_into_alternate_highspeed(&pin_data[13], 12); + pin_into_alternate_highspeed(&pin_data[14], 12); + pin_into_alternate_highspeed(&pin_data[15], 12); + pin_into_alternate_highspeed(&pin_data[16], 12); + pin_into_alternate_highspeed(&pin_data[17], 12); + pin_into_alternate_highspeed(&pin_data[18], 12); + pin_into_alternate_highspeed(&pin_data[19], 12); + pin_into_alternate_highspeed(&pin_data[20], 12); + pin_into_alternate_highspeed(&pin_data[21], 12); + pin_into_alternate_highspeed(&pin_data[22], 12); + pin_into_alternate_highspeed(&pin_data[23], 12); + pin_into_alternate_highspeed(&pin_data[24], 12); + pin_into_alternate_highspeed(&pin_data[25], 12); + pin_into_alternate_highspeed(&pin_data[26], 12); + pin_into_alternate_highspeed(&pin_data[27], 12); + pin_into_alternate_highspeed(&pin_data[28], 12); + pin_into_alternate_highspeed(&pin_data[29], 12); + pin_into_alternate_highspeed(&pin_data[30], 12); + pin_into_alternate_highspeed(&pin_data[31], 12); + + pin_into_alternate_highspeed(&pin_nbl[0], 12); + pin_into_alternate_highspeed(&pin_nbl[1], 12); + pin_into_alternate_highspeed(&pin_nbl[2], 12); + pin_into_alternate_highspeed(&pin_nbl[3], 12); + + pin_into_alternate_highspeed(&pin_sdcke1, 12); + pin_into_alternate_highspeed(&pin_sdclk, 12); + pin_into_alternate_highspeed(&pin_sdncas, 12); + pin_into_alternate_highspeed(&pin_sdne1, 12); + pin_into_alternate_highspeed(&pin_sdras, 12); + pin_into_alternate_highspeed(&pin_sdnwe, 12); + + fmc_sdram_configure(&fmc, SDRAM_BANK2, sdram_config, sdram_timing, sdram_mode_register); + } + + uint32_t* sdram_data = (uint32_t*)fmc_sdram_allocate(&fmc, SDRAM_BANK2, 1024); + + for (uint32_t i = 0; i < 1024/4; i++) { + *(sdram_data + i) = i; + } // Pins init pin_t led1; @@ -118,8 +287,6 @@ void main() exti_external_interrupt(&exti_wkup, EXTI_GPIOC); exti_rising_interrupt(&exti_wkup); exti_enable_interrupt(&exti_wkup); - /* NVIC_SetPriority(EXTI15_10_IRQn, 2); */ - /* NVIC_EnableIRQ(EXTI15_10_IRQn); */ __enable_irq(); @@ -154,10 +321,8 @@ void main() pin_into_alternate_highspeed(&ulpi_d6, 10); pin_into_alternate_highspeed(&ulpi_d7, 10); - // TODO: ? pin_into_input_highspeed(&otg_hs_overcurrent); - // TODO: why can't I send string descriptors? void *usb_dev = usb_device_init(USB_OTG_HS1, &USB_CLASS_CDC_ACM, 0x1234, 0x1111, u"Frantisek Bohacek", u"Display", 1, NULL); -- 2.48.1