Guest User

Untitled

a guest
Nov 3rd, 2025
37
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 22.38 KB | None | 0 0
  1. #pragma once
  2.  
  3.  
  4. #ifdef __cplusplus
  5. extern "C" {
  6.  
  7.  
  8.  
  9. #endif
  10.  
  11. #include "stm32u5xx.h"
  12.  
  13. /**
  14.  *Helpers to access different STM32 USB registers.
  15.  */
  16.  
  17. #define FSDEV_EP_COUNT     8
  18. #define FSDEV_PMA_SIZE     2048u   // 2 KB packet buffer, 32-bit access
  19. #define FSDEV_PMA_STRIDE   1       // word stride (32-bit bus)
  20.  
  21. #ifndef FSDEV_REG_BASE
  22. #define FSDEV_REG_BASE   (USB_DRD_BASE) // BASE USB REGISTER
  23. #endif
  24.  
  25. #define _va32 volatile  //__attribute__ ((aligned(4)))
  26.  
  27. typedef struct {
  28.     struct {
  29.         _va32 uint32_t reg;
  30.     } CHEPnR[FSDEV_EP_COUNT];
  31.  
  32.     _va32 uint32_t RESERVED7[8]; // Reserved
  33.     _va32 uint32_t CNTR; // 40: Control register
  34.     _va32 uint32_t ISTR; // 44: Interrupt status register
  35.     _va32 uint32_t FNR; // 48: Frame number register
  36.     _va32 uint32_t DADDR; // 4C: Device address register
  37.     _va32 uint32_t _reserved_old_BTABLE; // 50: Buffer Table address register (16-bit only)
  38.     _va32 uint32_t LPMCSR; // 54: LPM Control and Status Register (32-bit only)
  39.     _va32 uint32_t BCDR; // 58: Battery Charging Detector Register (32-bit only)
  40. } usb_reg_t;
  41.  
  42. #define USB_REG ((volatile usb_reg_t*)FSDEV_REG_BASE)
  43.  
  44. typedef struct {
  45.     struct {
  46.         _va32 uint32_t txrx;
  47.         _va32 uint32_t rxtx;
  48.     } btable[FSDEV_EP_COUNT];
  49.  
  50.     _va32 uint8_t free_mem[496]; // 64 -> size of btable. We have 2048. Since 32 bit word, 2048 - 64 = 1984 bytes = 496 words
  51. } usb_sram_t;
  52.  
  53.  
  54. #define USB_SRAM ((volatile usb_sram_t*) USB_DRD_PMAADDR)
  55.  
  56. static inline void fsdev_usb_set_global_interrupt(bool enabled) {
  57.     if (enabled) {
  58.         // printf("Enabling global USB interrupt\r\n");
  59.         HAL_NVIC_EnableIRQ(USB_IRQn);
  60.     } else {
  61.         // printf("Disabling global USB interrupt\r\n");
  62.         HAL_NVIC_DisableIRQ(USB_IRQn);
  63.     }
  64. }
  65.  
  66. // Reset control register
  67. static inline void fsdev_cntr_reset() {
  68.     USB_REG->CNTR = 0x00000003; // Reset + Power down, reset state according to docs
  69. }
  70.  
  71. // reset (clear) interrupt status register
  72. static inline void fsdev_istr_reset() {
  73.     USB_REG->ISTR = 0L;
  74. }
  75.  
  76.  
  77. #define USB_ISTR_RC_W0_MASK ( USB_ISTR_DCON | USB_ISTR_THR512 | USB_ISTR_PMAOVR | USB_ISTR_ERR | USB_ISTR_WKUP | USB_ISTR_SUSP \
  78.     | USB_ISTR_RESET | USB_ISTR_SOF | USB_ISTR_ESOF | USB_ISTR_L1REQ )
  79.  
  80. /**
  81.  * Clears the specified interrupt flags in the ISTR register.
  82.  * The USB_ISTR only allows writing to some pins.
  83.  * To avoid spurious clearing (hardware setting bits while we have old value in memory)
  84.  * we set the bits we want to clear to 0, and all other bits to 1.
  85.  * @param mask
  86.  */
  87. static inline void fsdev_istr_clear_irq(uint32_t mask) {
  88.     USB_REG->ISTR = ~(USB_ISTR_RC_W0_MASK & mask);
  89. }
  90.  
  91. static inline uint8_t fsdev_istr_read_idn(volatile uint32_t *istr) {
  92.     return (*istr & USB_ISTR_IDN) >> USB_ISTR_IDN_Pos;
  93. }
  94.  
  95. typedef enum {
  96.     FSDEV_CHEP_STATUS_DISABLED = 0b00,
  97.     FSDEV_CHEP_STATUS_STALL = 0b01,
  98.     FSDEV_CHEP_STATUS_NAK = 0b10,
  99.     FSDEV_CHEP_STATUS_VALID = 0b11
  100. } FsdevChepStatus;
  101.  
  102. typedef enum {
  103.     FSDEV_CHEP_TYPE_BULK = 0b00,
  104.     FSDEV_CHEP_TYPE_CONTROL = 0b01,
  105.     FSDEV_CHEP_TYPE_ISOCHRONOUS = 0b10,
  106.     FSDEV_CHEP_TYPE_INTERRUPT = 0b11
  107. } FsdevChepType;
  108.  
  109.  
  110. // The following masks are for some reason missing in the HAL headers
  111. #define USB_CHEP_THREE_ERR_RX_Pos     (29UL)
  112. #define USB_CHEP_THREE_ERR_RX_Msk     (0x3UL << USB_CHEP_THREE_ERR_RX_Pos) /*!< 0x60000000 */
  113. #define USB_CHEP_THREE_ERR_RX         USB_CHEP_THREE_ERR_RX_Msk            /*!< Three consecutive IN transaction errors */
  114.  
  115.  
  116.  
  117. #define USB_CHEP_THREE_ERR_TX_Pos     (27UL)
  118. #define USB_CHEP_THREE_ERR_TX_Msk     (0x3UL << USB_CHEP_THREE_ERR_TX_Pos) /*!< 0x18000000 */
  119. #define USB_CHEP_THREE_ERR_TX         USB_CHEP_THREE_ERR_TX_Msk            /*!< Three consecutive OUT/SETUP transaction errors */
  120.  
  121.  
  122.  
  123. // W0 (write 0 to clear, 1 indifferent) pins in CHEP
  124. #define USB_CHEP_RC_W0_MASK (USB_CHEP_ERRRX | USB_CHEP_ERRTX | USB_CHEP_THREE_ERR_RX | USB_CHEP_THREE_ERR_TX | \
  125.      USB_CHEP_NAK | USB_CHEP_VTRX | USB_CHEP_VTTX)
  126. // rw pins in CHEP
  127. #define USB_CHEP_RW_MASK (USB_CHEP_DEVADDR | USB_CHEP_UTYPE | USB_CHEP_LSEP | USB_CHEP_ADDR | USB_EP_KIND | USB_CHEP_SETUP)
  128. // Toglge pins in CHEP
  129. #define USB_CHEP_T_MASK (USB_CHEP_DTOG_RX | USB_CHEP_RX_STRX | USB_CHEP_DTOG_TX | USB_CHEP_TX_STTX)
  130.  
  131. static inline uint32_t _bf_get(uint32_t reg, uint32_t mask, unsigned pos) {
  132.     return (reg & mask) >> pos;
  133. }
  134.  
  135. static inline uint32_t _bf_prep(uint32_t mask, unsigned pos, uint32_t v) {
  136.     return (v << pos) & mask;
  137. }
  138.  
  139. static inline void fsdev_chep_write_rw(volatile uint32_t *chep,
  140.                                        uint32_t field_mask, unsigned field_pos,
  141.                                        uint32_t value) {
  142.     uint32_t r = *chep;
  143.     uint32_t desired = (r & ~field_mask) | _bf_prep(field_mask, field_pos, value);
  144.  
  145.     // 1 → keep rc_w0 unchanged; 0 → keep t unchanged
  146.     uint32_t w = desired;
  147.     w |= USB_CHEP_RC_W0_MASK;
  148.     w &= ~USB_CHEP_T_MASK;
  149.  
  150.     *chep = w;
  151. }
  152.  
  153. static inline void fsdev_chep_write_t_field(volatile uint32_t *chep,
  154.                                             uint32_t field_mask, unsigned field_pos,
  155.                                             uint32_t target) {
  156.     uint32_t r = *chep;
  157.     uint32_t current = _bf_get(r, field_mask, field_pos);
  158.     uint32_t toggles = ((current ^ target) << field_pos) & field_mask;
  159.  
  160.     // Start from current: preserve RW fields exactly as they are.
  161.     uint32_t w = r;
  162.  
  163.     // rc_w0 invariants: write 1 to "keep" (except any we explicitly clear elsewhere)
  164.     w |= USB_CHEP_RC_W0_MASK;
  165.  
  166.     // t invariants: default 0 = don't toggle
  167.     w &= ~USB_CHEP_T_MASK;
  168.  
  169.     // Apply required toggles (write 1 only where a toggle is needed)
  170.     w |= toggles;
  171.  
  172.     *chep = w;
  173. }
  174.  
  175.  
  176. static inline void fsdev_chep_clear_rcw0(volatile uint32_t *chep, uint32_t mask) {
  177.     uint32_t r = *chep;
  178.  
  179.     // Only clear bits that are both rc_w0 and requested in mask
  180.     uint32_t to_clear = mask & USB_CHEP_RC_W0_MASK;
  181.  
  182.     // Base: start from current value, set those rc_w0 bits to 0
  183.     uint32_t w = r & ~to_clear;
  184.  
  185.     // Set invariants for other categories:
  186.     w |= (USB_CHEP_RC_W0_MASK & ~to_clear); // 1 → keep rc_w0 not being cleared
  187.     w &= ~USB_CHEP_T_MASK; // 0 → keep t unchanged
  188.  
  189.     *chep = w;
  190. }
  191.  
  192. static inline FsdevChepStatus fsdev_chep_get_rx_status(uint32_t chep) {
  193.     return (FsdevChepStatus) _bf_get(chep, USB_CHEP_RX_STRX, USB_CHEP_RX_STRX_Pos);
  194. }
  195.  
  196. static inline void fsdev_chep_set_rx_status(volatile uint32_t *chep, FsdevChepStatus s) {
  197.     fsdev_chep_write_t_field(chep, USB_CHEP_RX_STRX, USB_CHEP_RX_STRX_Pos, (uint32_t) s & 0x3u);
  198. }
  199.  
  200. static inline FsdevChepStatus fsdev_chep_get_tx_status(uint32_t chep) {
  201.     return (FsdevChepStatus) _bf_get(chep, USB_CHEP_TX_STTX, USB_CHEP_TX_STTX_Pos);
  202. }
  203.  
  204. static inline void fsdev_chep_set_tx_status(volatile uint32_t *chep, FsdevChepStatus s) {
  205.     fsdev_chep_write_t_field(chep, USB_CHEP_TX_STTX, USB_CHEP_TX_STTX_Pos, (uint32_t) s & 0x3u);
  206. }
  207.  
  208. static inline FsdevChepType fsdev_chep_get_type(uint32_t chep) {
  209.     return (FsdevChepType) _bf_get(chep, USB_CHEP_UTYPE, USB_CHEP_UTYPE_Pos);
  210. }
  211.  
  212. static inline void fsdev_chep_set_type(volatile uint32_t *chep, FsdevChepType t) {
  213.     fsdev_chep_write_rw(chep, USB_CHEP_UTYPE, USB_CHEP_UTYPE_Pos, (uint32_t) t & 0x3u);
  214. }
  215.  
  216. static inline uint32_t fsdev_chep_get_devaddr(uint32_t chep) {
  217.     return _bf_get(chep, USB_CHEP_DEVADDR, USB_CHEP_DEVADDR_Pos);
  218. }
  219.  
  220. static inline void fsdev_chep_set_devaddr(volatile uint32_t *chep, uint32_t addr) {
  221.     fsdev_chep_write_rw(chep, USB_CHEP_DEVADDR, USB_CHEP_DEVADDR_Pos, addr & 0x7Fu);
  222. }
  223.  
  224. /**
  225.  * USB SRAM HELPERS
  226.  * The USB SRAM fist features a 64 byte BTABLE (buffer table) area,
  227.  * followed by free memory area.
  228.  */
  229.  
  230. #define FSDEV_BD_ADDR_Pos     0u
  231. #define FSDEV_BD_ADDR_Msk     0x0000FFFFu
  232.  
  233. #define FSDEV_BD_COUNT_TX_Pos 16u
  234. #define FSDEV_BD_COUNT_TX_Msk 0x03FF0000u
  235.  
  236. #define FSDEV_BD_BLSIZE_Pos   31u
  237. #define FSDEV_BD_BLSIZE_Msk   0x80000000u
  238. #define FSDEV_BD_NUMBLK_Pos   26u
  239. #define FSDEV_BD_NUMBLK_Msk   0x7C000000u
  240. #define FSDEV_BD_COUNT_RX_Pos 16u
  241. #define FSDEV_BD_COUNT_RX_Msk 0x03FF0000u
  242.  
  243. static inline void fsdev_bd_tx_set_addr_ptr(volatile uint32_t *txrx, uint16_t pma_off) {
  244.     if (pma_off & 0x3) {
  245.         printf("[ERROR] fsdev_bd_tx_set_addr_ptr: Address 0x%04X not word-aligned!\n", pma_off);
  246.         // Optionally: return early, assert, or handle error
  247.     }
  248.     uint32_t v = *txrx;
  249.     v &= ~FSDEV_BD_ADDR_Msk;
  250.     v |= (uint32_t) (pma_off & 0xFFFCu);
  251.     *txrx = v;
  252.  
  253.     // printf("[fsdev_bd_tx_set_addr_ptr] Set TX addr_ptr to 0x%04X, raw reg now 0x%08X\r\n",
  254.            // pma_off & 0xFFFCu, *txrx);
  255. }
  256.  
  257. static inline void fsdev_bd_tx_set_count_ptr(volatile uint32_t *txrx, uint16_t count) {
  258.     uint32_t v = *txrx;
  259.     v &= ~FSDEV_BD_COUNT_TX_Msk;
  260.     v |= ((uint32_t) (count & 0x03FFu) << FSDEV_BD_COUNT_TX_Pos);
  261.     *txrx = v;
  262.  
  263.     // printf("[fsdev_bd_tx_set_count_ptr] Set TX count to %u, raw reg now 0x%08X\r\n",
  264.            // count, *txrx);
  265. }
  266.  
  267. static inline void fsdev_bd_tx(volatile uint32_t *txrx, uint16_t pma_off, uint16_t count) {
  268.     // [16:25] -> count
  269.     // [0:15]  -> addr
  270.     if (pma_off & 0x3) {
  271.         printf("[ERROR] fsdev_bd_tx_set: Address 0x%04X not word-aligned!\n", pma_off);
  272.     }
  273.     // Build clean descriptor from zero
  274.     uint32_t bd_val = 0;
  275.  
  276.     // printf("Writing pma offset %x, count %u to BD\r\n", pma_off, count);
  277.  
  278.     bd_val |= (uint32_t) (pma_off & 0xFFFCu);
  279.     bd_val |= ((uint32_t) (count & 0x03FFu) << FSDEV_BD_COUNT_TX_Pos);
  280.  
  281.     *txrx = bd_val;
  282. }
  283.  
  284.  
  285.  
  286. static inline uint16_t fsdev_bd_tx_get_addr_ptr(volatile uint32_t *txrx) {
  287.     return (uint16_t) (*txrx & FSDEV_BD_ADDR_Msk);
  288. }
  289.  
  290.  
  291. static inline uint16_t fsdev_bd_tx_get_count_ptr(volatile uint32_t *txrx) {
  292.     return (uint16_t) ((*txrx & FSDEV_BD_COUNT_TX_Msk) >> FSDEV_BD_COUNT_TX_Pos);
  293. }
  294.  
  295. static inline void fsdev_bd_rx_set_addr_ptr(volatile uint32_t *rxtx, uint16_t pma_off) {
  296.     if (pma_off & 0x3) {
  297.         printf("[ERROR] fsdev_bd_tx_set_addr_ptr: Address 0x%04X not word-aligned!\n", pma_off);
  298.         // Optionally: return early, assert, or handle error
  299.     }
  300.     uint32_t v = *rxtx;
  301.     v &= ~FSDEV_BD_ADDR_Msk;
  302.     v |= (uint32_t) (pma_off & 0xFFFCu);
  303.     *rxtx = v;
  304. }
  305.  
  306. static inline uint16_t fsdev_bd_rx_get_addr_ptr(volatile uint32_t *rxtx) {
  307.     return fsdev_bd_tx_get_addr_ptr(rxtx); // same address layout
  308. }
  309.  
  310. static inline void fsdev_bd_rx_set_count_ptr(volatile uint32_t *rxtx, uint16_t alloc_size) {
  311.     uint32_t v = *rxtx;
  312.  
  313.     // Clear previous settings
  314.     v &= ~(FSDEV_BD_BLSIZE_Msk | FSDEV_BD_NUMBLK_Msk | FSDEV_BD_COUNT_RX_Msk);
  315.  
  316.     // Configure block size (BLSIZE) and number of blocks (NUM_BLOCK)
  317.     if (alloc_size <= 62) {
  318.         // Use 2-byte blocks (BLSIZE=0)
  319.         v |= (0 << FSDEV_BD_BLSIZE_Pos);
  320.         v |= ((alloc_size / 2) << FSDEV_BD_NUMBLK_Pos);
  321.     } else {
  322.         // Use 32-byte blocks (BLSIZE=1)
  323.         v |= (1 << FSDEV_BD_BLSIZE_Pos);
  324.         v |= ((alloc_size / 32) << FSDEV_BD_NUMBLK_Pos);
  325.     }
  326.  
  327.     *rxtx = v;
  328. }
  329.  
  330.  
  331.  
  332.  
  333. #define USB_PMA_FIRST_FREE 0x40  // First free byte offset in PMA (after BTABLE)
  334.  
  335. /**
  336.  * Align value up to next multiple of 4.
  337.  * Is used as PMA access uses 32-bit words.
  338.  */
  339. static inline uint16_t _align_up4(uint16_t value) {
  340.     uint16_t remainder = value % 4;
  341.     if (remainder == 0)
  342.         return value; // already aligned
  343.     else
  344.         return (uint16_t) (value + (4 - remainder)); // round up to next multiple of 4
  345. }
  346.  
  347. typedef struct {
  348.     uint16_t next; /* next free byte offset (relative to PMA base) */
  349. } UsbPmaAllocator;
  350.  
  351. static inline void usb_pma_allocator_init(UsbPmaAllocator *a) {
  352.     a->next = USB_PMA_FIRST_FREE;
  353. }
  354.  
  355. /**
  356.  * Allocate `size_bytes` bytes from PMA.
  357.  * Return -1 if not enough space.
  358.  * @param allocator USB PMA allocator
  359.  * @param size_bytes Number of bytes to allocate
  360.  * @return
  361.  */
  362. static inline uint16_t usb_pma_alloc(UsbPmaAllocator *allocator, uint16_t size_bytes) {
  363.     const uint16_t start = _align_up4(allocator->next);
  364.  
  365.     const uint32_t end32 = (uint32_t) start + (uint32_t) size_bytes;
  366.  
  367.     /* end is exclusive; must not exceed the total PMA size */
  368.     if (end32 > (uint32_t) FSDEV_PMA_SIZE) {
  369.         return -1;
  370.     }
  371.  
  372.     allocator->next = (int16_t) end32;
  373.  
  374.     // printf("[usb_pma_alloc] Allocated %u bytes at PMA offset 0x%04X, next free at 0x%04X\r\n",
  375.            // size_bytes, start, allocator->next);
  376.  
  377.     return start;
  378. }
  379.  
  380. /* Bytes consumed from PMA base (0..USB_PMA_LIMIT) */
  381. static inline uint16_t usb_pma_bytes_used(const UsbPmaAllocator *a) {
  382.     return a->next;
  383. }
  384.  
  385. /* Remaining bytes (clamped at 0) */
  386. static inline uint16_t usb_pma_bytes_free(const UsbPmaAllocator *a) {
  387.     return (FSDEV_PMA_SIZE > a->next) ? (uint16_t) (FSDEV_PMA_SIZE - a->next) : (uint16_t) 0;
  388. }
  389.  
  390. /* Pack 0..3 bytes into a 32-bit word (little-endian), zero-padding */
  391. static inline uint32_t fsdev_pack_le32(const uint8_t *s, uint16_t n) {
  392.     uint32_t w = 0;
  393.     if (n >= 1) w |= (uint32_t) s[0];
  394.     if (n >= 2) w |= (uint32_t) s[1] << 8;
  395.     if (n >= 3) w |= (uint32_t) s[2] << 16;
  396.     return w;
  397. }
  398.  
  399. /* Unpack up to 3 bytes from a 32-bit word (little-endian) */
  400. static inline void fsdev_unpack_le32(uint32_t w, uint8_t *d, uint16_t n) {
  401.     if (n >= 1) d[0] = (uint8_t) (w & 0xFF);
  402.     if (n >= 2) d[1] = (uint8_t) ((w >> 8) & 0xFF);
  403.     if (n >= 3) d[2] = (uint8_t) ((w >> 16) & 0xFF);
  404. }
  405.  
  406. //#define FSDEV_PMA_U32_BASE  ((volatile uint32_t *)(USB_DRD_PMAADDR)) // PMA as 32-bit pointer
  407. static inline void fsdev_pma_write(uint16_t dst_off, const void *src, uint16_t len) {
  408.     if ((dst_off & 0x3u) != 0u) {
  409.         printf("[fsdev_pma_write] ERROR: PMA offset 0x%04X not 4-byte aligned\r\n", dst_off);
  410.         return;
  411.     }
  412.  
  413.     const uint8_t *s = (const uint8_t *) src;
  414.  
  415.     // Access entire PMA as 32-bit array (not just free_mem)
  416.     volatile uint32_t *pma = (volatile uint32_t *) USB_DRD_PMAADDR;
  417.     uint32_t idx = dst_off >> 2;  // Convert byte offset to word index
  418.  
  419.     // printf("[fsdev_pma_write] Writing %u bytes to PMA offset 0x%04X (idx=%u)\r\n", len, dst_off, idx);
  420.  
  421.     while (len >= 4u) {
  422.         uint32_t w = s[0] | (s[1] << 8) | (s[2] << 16) | (s[3] << 24);
  423.         pma[idx++] = w;
  424.         // printf("[fsdev_pma_write] Wrote 0x%08X\r\n", w);
  425.         s += 4;
  426.         len -= 4;
  427.     }
  428.  
  429.     if (len != 0u) {
  430.         uint32_t w = fsdev_pack_le32(s, len);
  431.         pma[idx] = w;
  432.         // printf("[fsdev_pma_write] Wrote tail 0x%08X for %u bytes\r\n", w, len);
  433.     }
  434. }
  435.  
  436. static inline void fsdev_pma_read(void *dst, uint16_t src_off, uint16_t len) {
  437.     if ((src_off & 0x3u) != 0u) {
  438.         printf("[fsdev_pma_read] ERROR: PMA offset 0x%04X not 4-byte aligned\r\n", src_off);
  439.         return;
  440.     }
  441.  
  442.     uint8_t *d = (uint8_t *) dst;
  443.  
  444.     // Access entire PMA as 32-bit array (not just free_mem)
  445.     volatile uint32_t *pma = (volatile uint32_t *) USB_DRD_PMAADDR;
  446.     uint32_t idx = src_off >> 2;  // Convert byte offset to word index
  447.  
  448.     // printf("[fsdev_pma_read] Reading %u bytes from PMA offset 0x%04X (idx=%u)\r\n", len, src_off, idx);
  449.  
  450.     while (len >= 4u) {
  451.         uint32_t w = pma[idx++];
  452.         d[0] = (uint8_t) w;
  453.         d[1] = (uint8_t) (w >> 8);
  454.         d[2] = (uint8_t) (w >> 16);
  455.         d[3] = (uint8_t) (w >> 24);
  456.         // printf("[fsdev_pma_read] Read 0x%08X\r\n", w);
  457.         d += 4;
  458.         len -= 4;
  459.     }
  460.  
  461.     if (len != 0u) {
  462.         uint32_t w = pma[idx];
  463.         fsdev_unpack_le32(w, d, len);
  464.         // printf("[fsdev_pma_read] Read tail 0x%08X for %u bytes\r\n", w, len);
  465.     }
  466. }
  467.  
  468.  
  469. /**
  470.  *
  471.  * PRINTING HELPERS FOR THE REGISTERS
  472.  *
  473.  */
  474.  
  475. static inline const char *yesno(bool v) {
  476.     return v ? "Yes" : "No";
  477. }
  478.  
  479. static inline const char *onoff(bool v) { return v ? "On" : "Off"; }
  480. static inline const char *setclr(bool v) { return v ? "Set" : "Clear"; }
  481. static inline const char *enable(bool v) { return v ? "Enabled" : "Disabled"; }
  482.  
  483. static inline void fsdev_usb_print_istr(uint32_t reg) {
  484.     printf("[USB_ISTR] = 0x%08lX\r\n", (unsigned long) reg);
  485.  
  486.     printf("  CTR:%s PMAOVR:%s ERR:%s WKUP:%s SUSP:%s RST_DCON:%s\r\n",
  487.            yesno(reg & USB_ISTR_CTR),
  488.            yesno(reg & USB_ISTR_PMAOVR),
  489.            yesno(reg & USB_ISTR_ERR),
  490.            yesno(reg & USB_ISTR_WKUP),
  491.            yesno(reg & USB_ISTR_SUSP),
  492.            yesno(reg & USB_ISTR_RESET));
  493.  
  494.     printf("  SOF:%s ESOF:%s L1REQ:%s THR512:%s DCON_STAT:%s DDISC:%s LS_DCON:%s\r\n",
  495.            yesno(reg & USB_ISTR_SOF),
  496.            yesno(reg & USB_ISTR_ESOF),
  497.            yesno(reg & USB_ISTR_L1REQ),
  498.            yesno(reg & USB_ISTR_THR512),
  499.            yesno(reg & USB_ISTR_DCON_STAT),
  500.            yesno(reg & USB_ISTR_DCON),
  501.            yesno(reg & USB_ISTR_LS_DCONN));
  502.  
  503.     const bool dir_rx = (reg & USB_ISTR_DIR) != 0;
  504.     const unsigned idn = (reg & USB_ISTR_IDN);
  505.     printf("  DIR:%s IDN:%u\r\n",
  506.            dir_rx ? "RX/OUT (host->device)" : "TX/IN (device->host)",
  507.            idn);
  508. }
  509.  
  510. static inline void fsdev_usb_print_cntr(uint32_t reg) {
  511.     printf("[USB_CNTR] = 0x%08lX\r\n", (unsigned long) reg);
  512.  
  513.     printf("  HOST:%s THR512M:%s CTRM:%s PMAOVRM:%s ERRM:%s WKUPM:%s SUSPM:%s\r\n",
  514.            (reg & USB_CNTR_HOST) ? "Enabled" : "Device",
  515.            onoff(reg & USB_CNTR_THR512M),
  516.            onoff(reg & USB_CNTR_CTRM),
  517.            onoff(reg & USB_CNTR_PMAOVRM),
  518.            onoff(reg & USB_CNTR_ERRM),
  519.            onoff(reg & USB_CNTR_WKUPM),
  520.            onoff(reg & USB_CNTR_SUSPM));
  521.  
  522.     printf("  RESETM:%s SOFM:%s ESOFM:%s L1REQM:%s L1RES:%s L2RES:%s SUSPEN:%s\r\n",
  523.            onoff(reg & USB_CNTR_RESETM),
  524.            onoff(reg & USB_CNTR_SOFM),
  525.            onoff(reg & USB_CNTR_ESOFM),
  526.            onoff(reg & USB_CNTR_L1REQM),
  527.            setclr(reg & USB_CNTR_L1RES),
  528.            setclr(reg & USB_CNTR_L2RES),
  529.            enable(reg & USB_CNTR_SUSPEN));
  530.  
  531.     printf("  SUSPRDY:%s PDWN:%s USBRST:%s\r\n",
  532.            yesno(reg & USB_CNTR_SUSPRDY),
  533.            onoff(reg & USB_CNTR_PDWN),
  534.            (reg & USB_CNTR_USBRST) ? "Active" : "Inactive");
  535. }
  536.  
  537.  
  538. static inline void fsdev_usb_print_chep(uint32_t reg, unsigned chep_n) {
  539.     const FsdevChepStatus rx = fsdev_chep_get_rx_status(reg);
  540.     const FsdevChepStatus tx = fsdev_chep_get_tx_status(reg);
  541.     const FsdevChepType tp = fsdev_chep_get_type(reg);
  542.  
  543.     static const char *stS[] = {"DIS", "STALL", "NAK", "VAL"};
  544.     static const char *tpS[] = {"BULK", "CTRL", "ISO", "INTR"};
  545.  
  546.     const unsigned ea = (unsigned) fsdev_chep_get_devaddr(reg);
  547.     const unsigned kind = (reg & USB_EP_KIND) ? 1u : 0u;
  548.     const unsigned setup = (reg & USB_CHEP_SETUP) ? 1u : 0u;
  549.  
  550.     const unsigned dtog_rx = (reg & USB_CHEP_DTOG_RX) ? 1u : 0u;
  551.     const unsigned dtog_tx = (reg & USB_CHEP_DTOG_TX) ? 1u : 0u;
  552.     const unsigned vtrx = (reg & USB_CHEP_VTRX) ? 1u : 0u;
  553.     const unsigned vttx = (reg & USB_CHEP_VTTX) ? 1u : 0u;
  554.     const unsigned errrx = (reg & USB_CHEP_ERRRX) ? 1u : 0u;
  555.     const unsigned errtx = (reg & USB_CHEP_ERRTX) ? 1u : 0u;
  556.     const unsigned nak = (reg & USB_CHEP_NAK) ? 1u : 0u;
  557.  
  558.     // Optional “three consecutive errors” bits (present on U5):
  559.     const unsigned three_rx = (reg & USB_CHEP_THREE_ERR_RX) ? 1u : 0u;
  560.     const unsigned three_tx = (reg & USB_CHEP_THREE_ERR_TX) ? 1u : 0u;
  561.  
  562.     printf("[CHEP%u] 0x%08lX  EA=%u  TYPE=%s  KIND=%u  SETUP=%u  RX:%s  TX:%s\r\n",
  563.            chep_n, (unsigned long) reg, ea, tpS[(unsigned) tp], kind, setup,
  564.            stS[(unsigned) rx], stS[(unsigned) tx]);
  565.  
  566.     printf("         DTOG_RX:%u DTOG_TX:%u  VTRX:%u VTTX:%u  ERRrx:%u ERRtx:%u  NAK:%u  3ERRrx:%u 3ERRtx:%u\r\n",
  567.            dtog_rx, dtog_tx, vtrx, vttx, errrx, errtx, nak, three_rx, three_tx);
  568. }
  569.  
  570. static inline void fsdev_usb_print_btable_at(volatile usb_sram_t *pma) {
  571.     printf("[BTABLE] base=%p, entries=%u\r\n", (void *) &pma->btable[0], (unsigned) FSDEV_EP_COUNT);
  572.  
  573.     for (unsigned n = 0; n < FSDEV_EP_COUNT; ++n) {
  574.         uint32_t tx = pma->btable[n].txrx;
  575.         uint32_t rx = pma->btable[n].rxtx;
  576.  
  577.         uint16_t addr_tx = (uint16_t) (tx & FSDEV_BD_ADDR_Msk);
  578.         uint16_t cnt_tx = (uint16_t) ((tx & FSDEV_BD_COUNT_TX_Msk) >> FSDEV_BD_COUNT_TX_Pos);
  579.  
  580.         uint16_t addr_rx = (uint16_t) (rx & FSDEV_BD_ADDR_Msk);
  581.         uint16_t cnt_rx = (uint16_t) ((rx & FSDEV_BD_COUNT_RX_Msk) >> FSDEV_BD_COUNT_RX_Pos);
  582.  
  583.         uint8_t bl = (uint8_t) ((rx & FSDEV_BD_BLSIZE_Msk) >> FSDEV_BD_BLSIZE_Pos); /* 0=2B blocks, 1=32B blocks */
  584.         uint8_t numblk = (uint8_t) ((rx & FSDEV_BD_NUMBLK_Msk) >> FSDEV_BD_NUMBLK_Pos);
  585.         uint16_t cap = (numblk == 0) ? 0 : (bl ? (uint16_t) (32u * numblk) : (uint16_t) (2u * numblk));
  586.  
  587.         /* Optional: flag misalignment if ADDR bits[1:0] are not 0 (should always be 0) */
  588.         const char *ax = ((addr_tx & 0x3u) == 0u) ? "" : "(!)";
  589.         const char *ar = ((addr_rx & 0x3u) == 0u) ? "" : "(!)";
  590.  
  591.         printf("  EP%u TX:A=0x%04X%s C=%3u  RX:A=0x%04X%s C=%3u  ALLOC=%3u (%s, nb=%u)\r\n",
  592.                n,
  593.                addr_tx, ax, (unsigned) cnt_tx,
  594.                addr_rx, ar, (unsigned) cnt_rx,
  595.                (unsigned) cap, bl ? "32B" : "2B", (unsigned) numblk);
  596.     }
  597. }
  598.  
  599. static inline void fsdev_usb_print_btable_entry(uint32_t bd, bool is_tx) {
  600.     const uint16_t addr = (uint16_t) (bd & FSDEV_BD_ADDR_Msk);
  601.     const int misal = (addr & 0x3u) != 0u;
  602.     if (is_tx) {
  603.         const uint16_t cnt_tx = (uint16_t) ((bd & FSDEV_BD_COUNT_TX_Msk) >> FSDEV_BD_COUNT_TX_Pos);
  604.         printf(" [BD TX] raw:0x%08lX  ADDR:0x%04X%s  CNT:%4u\r\n",
  605.                (unsigned long) bd,
  606.                addr, misal ? "(!)" : "",
  607.                (unsigned) cnt_tx);
  608.     } else {
  609.         const uint16_t cnt_rx = (uint16_t) ((bd & FSDEV_BD_COUNT_RX_Msk) >> FSDEV_BD_COUNT_RX_Pos);
  610.         const uint8_t bl = (uint8_t) ((bd & FSDEV_BD_BLSIZE_Msk) >> FSDEV_BD_BLSIZE_Pos); /* 0=2B, 1=32B */
  611.         const uint8_t numblk = (uint8_t) ((bd & FSDEV_BD_NUMBLK_Msk) >> FSDEV_BD_NUMBLK_Pos);
  612.         const uint16_t cap = (numblk == 0) ? 0u : (uint16_t) (bl ? (32u * numblk) : (2u * numblk));
  613.         printf(" [BD RX] raw:0x%08lX  ADDR:0x%04X%s  CNT:%4u  ALLOC:%4u (%s, nb=%u)\r\n",
  614.                (unsigned long) bd,
  615.                addr, misal ? "(!)" : "",
  616.                (unsigned) cnt_rx,
  617.                (unsigned) cap, bl ? "32B" : "2B", (unsigned) numblk);
  618.     }
  619. }
  620.  
  621. static inline void fsdev_usb_print_pma(const UsbPmaAllocator *a) {
  622.     printf("[PMA] used=%u, free=%u, limit=%u\r\n",
  623.            (unsigned) usb_pma_bytes_used(a),
  624.            (unsigned) usb_pma_bytes_free(a),
  625.            (unsigned) FSDEV_PMA_SIZE);
  626. }
  627.  
  628. #ifdef __cplusplus
  629. }
  630. #endif
  631.  
Advertisement
Add Comment
Please, Sign In to add comment