Compare commits

...

10 Commits

Author SHA1 Message Date
ALTracer
caaf002f09 usb/dwc: Enable (unaligned) access to OTG_FIFO for ARMv8-M Main 2025-09-21 16:52:00 +03:00
ALTracer
0efe43d43e cm3: itm: Enable for ARMv8-M Main (Cortex-M33) 2025-09-21 16:51:45 +03:00
Chuck McManis
8a96a9d95a Additional updates to STM32U5
Reference manual indicates that SRAM4 is always at 0x28000000 which makes
it generally discontinuous with other RAM so RAM values that included it were
reduced by 16K and the STM32U5 END line updated to have both the SRAM4 size
and offset.
2025-07-14 12:07:51 -07:00
Chuck McManis
842d64152c This adds the STM32U5 Family to devices.data
Taken from RM0456, Rev 6. This adds STM32U535, STM32U545, STM32U575, STM32U585,
STM32U595, STM32U5A, STM32U5F, and STM32U5G.
2025-07-13 20:56:46 -07:00
Benedikt Spranger
a9b71e2f8c stm32g4: Add EXTI support
The STM32G4xx series contain two regular EXTI v1 blocks; one at offset 0x00,
the other at offset 0x20.
Add support for EXTI.

Signed-off-by: Benedikt Spranger <b.spranger@linutronix.de>
2025-07-13 16:36:11 -07:00
jsphuebner
886cd116ff Corrected documentation for adc_read_injected 2025-07-13 16:11:46 -07:00
johannes
d1b43a7bb9 Made adc_read_injected() return signed int because result can become negative
Added function can_fifo_pending() - number of pending RX messages
can_receive() returns number of pending messages prior to release
2025-07-13 16:11:46 -07:00
andrewmcg1
3b892e4a18 Added functions for entering l4 power modes 2025-07-13 16:08:28 -07:00
Stoyan Shopov
49e347923b Fix usb_dwc_common.c endpoint initialization
This commit addresses libopencm3 issue #1242:
https://github.com/libopencm3/libopencm3/issues/1242
2025-07-13 10:32:00 +01:00
Benedikt Spranger
8526d7095c stm32g4: rcc: Add support for 24MHz external clocks
The ST Nucleo 64 boards NUCLEO-G431RB, NUCLEO-G474RE and NUCLEO-G491RE
are equipped with a 24 MHz crystal. Add RCC clock support for these
boards.

Signed-off-by: Benedikt Spranger <b.spranger@linutronix.de>
2025-07-12 10:44:07 -07:00
17 changed files with 272 additions and 20 deletions

View File

@@ -27,8 +27,8 @@
*/
/* Those defined only on ARMv7 and above */
#if !defined(__ARM_ARCH_7M__) && !defined(__ARM_ARCH_7EM__)
#error "Instrumentation Trace Macrocell not available in CM0"
#if !defined(__ARM_ARCH_7M__) && !defined(__ARM_ARCH_7EM__) && !defined(__ARM_ARCH_8M_MAIN__)
#error "Instrumentation Trace Macrocell not available in CM0 or CM23"
#endif
/* --- ITM registers ------------------------------------------------------- */

View File

@@ -26,7 +26,7 @@
#define PPBI_BASE (0xE0000000U)
/* Those defined only on ARMv7 and above */
#if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__)
#if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__) || defined(__ARM_ARCH_8M_MAIN__)
/* ITM: Instrumentation Trace Macrocell */
#define ITM_BASE (PPBI_BASE + 0x0000)

View File

@@ -554,6 +554,10 @@ struct scb_exception_stack_frame {
} while (0)
void scb_reset_system(void) __attribute__((noreturn));
void scb_set_sleepdeep(void);
void scb_clear_sleepdeep(void);
void scb_set_sleeponexit(void);
void scb_clear_sleeponexit(void);
/* Those defined only on ARMv7 and above */
#if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__)

View File

@@ -668,12 +668,13 @@ void can_disable_irq(uint32_t canport, uint32_t irq);
int can_transmit(uint32_t canport, uint32_t id, bool ext, bool rtr,
uint8_t length, uint8_t *data);
void can_receive(uint32_t canport, uint8_t fifo, bool release, uint32_t *id,
uint32_t can_receive(uint32_t canport, uint8_t fifo, bool release, uint32_t *id,
bool *ext, bool *rtr, uint8_t *fmi, uint8_t *length,
uint8_t *data, uint16_t *timestamp);
void can_fifo_release(uint32_t canport, uint8_t fifo);
bool can_available_mailbox(uint32_t canport);
uint32_t can_fifo_pending(uint32_t canport, uint8_t fifo);
END_DECLS
/**@}*/

View File

@@ -399,7 +399,7 @@ void adc_set_right_aligned(uint32_t adc);
bool adc_eoc(uint32_t adc);
bool adc_eoc_injected(uint32_t adc);
uint32_t adc_read_regular(uint32_t adc);
uint32_t adc_read_injected(uint32_t adc, uint8_t reg);
int32_t adc_read_injected(uint32_t adc, uint8_t reg);
void adc_set_continuous_conversion_mode(uint32_t adc);
void adc_set_single_conversion_mode(uint32_t adc);
void adc_set_regular_sequence(uint32_t adc, uint8_t length, uint8_t channel[]);

View File

@@ -44,6 +44,8 @@
# include <libopencm3/stm32/u5/exti.h>
#elif defined(STM32G0)
# include <libopencm3/stm32/g0/exti.h>
#elif defined(STM32G4)
# include <libopencm3/stm32/g4/exti.h>
#elif defined(STM32H7)
# include <libopencm3/stm32/h7/exti.h>
#else

View File

@@ -0,0 +1,59 @@
/** @defgroup exti_defines EXTI Defines
*
* @brief <b>Defined Constants and Types for the STM32G4xx External Interrupts
* </b>
*
* @ingroup STM32G4xx_defines
*
* @author @htmlonly &copy; @endhtmlonly 2023
* Benedikt Spranger <b.spranger@linutronix.de>
*
* @version 1.0.0
*
* @date 19 February 2023
*
* LGPL License Terms @ref lgpl_license
*/
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2023 Benedikt Spranger <b.spranger@linutronix.de>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef LIBOPENCM3_EXTI_H
#define LIBOPENCM3_EXTI_H
/**@{*/
#include <libopencm3/stm32/common/exti_common_all.h>
#include <libopencm3/stm32/common/exti_common_v1.h>
/* --- EXTI registers ------------------------------------------------------ */
#define EXTI_IMR1 EXTI_IMR
#define EXTI_EMR1 EXTI_EMR
#define EXTI_RTSR1 EXTI_RTSR
#define EXTI_FTSR1 EXTI_FTSR
#define EXTI_SWIER1 EXTI_SWIER
#define EXTI_PR1 EXTI_PR
#define EXTI_IMR2 MMIO32(EXTI_BASE + 0x20)
#define EXTI_EMR2 MMIO32(EXTI_BASE + 0x24)
#define EXTI_RTSR2 MMIO32(EXTI_BASE + 0x28)
#define EXTI_FTSR2 MMIO32(EXTI_BASE + 0x2C)
#define EXTI_SWIER2 MMIO32(EXTI_BASE + 0x30)
#define EXTI_PR2 MMIO32(EXTI_BASE + 0x34)
/**@}*/
#endif

View File

@@ -766,6 +766,7 @@ extern const struct rcc_clock_scale rcc_hsi_configs[RCC_CLOCK_3V3_END];
extern const struct rcc_clock_scale rcc_hse_8mhz_3v3[RCC_CLOCK_3V3_END];
extern const struct rcc_clock_scale rcc_hse_12mhz_3v3[RCC_CLOCK_3V3_END];
extern const struct rcc_clock_scale rcc_hse_16mhz_3v3[RCC_CLOCK_3V3_END];
extern const struct rcc_clock_scale rcc_hse_24mhz_3v3[RCC_CLOCK_3V3_END];
enum rcc_osc {
RCC_HSI48,

View File

@@ -77,11 +77,15 @@ specific memorymap.h header before including this header file.*/
#define PWR_CR1_LPMS_SHIFT 0
#define PWR_CR1_LPMS_MASK 0x07
/** @defgroup pwr_cr1_lpms LPMS mode selection
* @ingroup STM32L4_pwr_defines
@{*/
#define PWR_CR1_LPMS_STOP_0 0
#define PWR_CR1_LPMS_STOP_1 1
#define PWR_CR1_LPMS_STOP_2 2
#define PWR_CR1_LPMS_STANDBY 3
#define PWR_CR1_LPMS_SHUTDOWN 4
/**@}*/
/* --- PWR_CR2 values ------------------------------------------------------- */
@@ -173,6 +177,10 @@ void pwr_set_vos_scale(enum pwr_vos_scale scale);
void pwr_disable_backup_domain_write_protect(void);
void pwr_enable_backup_domain_write_protect(void);
void pwr_enable_low_power_run(void);
void pwr_disable_low_power_run(void);
void pwr_set_low_power_mode_selection(uint32_t lpms);
END_DECLS
#endif

View File

@@ -186,8 +186,34 @@ stm32f7[67][89]?i* stm32f7ccm ROM=2048K RAM=384K CCM=128K
stm32f750* stm32f7ccm ROM=64K RAM=256K CCM=64K
stm32f730* stm32f7ccm ROM=64K RAM=192K CCM=64K
# on u5 the RAM1 and RAM2 can be combined to create one bigger bank
stm32u5[78]5* stm32u5 ROM=2048K RAM=768K RAM3=512K RAM4=4K
# STM32U5 family
# These parts have (at this writing) up to 7 SRAM sections (1 - 7) but not
# all parts have all SRAM. For example the smallest parts (535/545) have
# SRAM1, SRAM2, and SRAM4 but are missing SRAM3. If you don't specify a
# flash size (trailing E/C/B/G/I/J) you get the smallest flash for that
# group
#
# RM0456, Rev 6 plus individual device data sheets.
# SRAM4 is added with the stm32u5 END line further down in the file
#
# STM32U535/U545 have SRAM1, 2, and 4 and 128K, 256K, and 512K of FLASH
stm32u5[34]5*e stm32u5 ROM=512K RAM=256K
stm32u5[34]5*c stm32u5 ROM=256K RAM=256K
stm32u5[34]5*b stm32u5 ROM=128K RAM=256K
stm32u5[34]5* stm32u5 ROM=128K RAM=256K
# STM32U575/U585 have SRAM1, SRAM2, SRAM3, SRAM4
stm32u575*g stm32u5 ROM=2048K RAM=752K
stm32u575*i stm32u5 ROM=1024K RAM=752K
stm32u575* stm32u5 ROM=1024K RAM=752K
stm32u585* stm32u5 ROM=2048K RAM=752K
# STM32U59* have SRAM1, SRAM2, SRAM3, SRAM4, SRAM5
stm32u59*j stm32u5 ROM=4096K RAM=2496K
stm32u59*i stm32u5 ROM=2048K RAM=2496K
stm32u59* stm32u5 ROM=2048K RAM=2495K
# STM32U5A* have same memories as 595 (1-5)
stm32u5a* stm32u5 ROM=4096K RAM=2495K
# STM32U5F* Adds SRAM6 and U5G dual banks flash (so 8192K but only 4096K active)
stm32u5[fg]* stm32u5 ROM=4096K RAM=3008K
stm32l01??3* stm32l0 ROM=8K RAM=2K
stm32l0[12]??4* stm32l0 ROM=16K RAM=2K
@@ -597,7 +623,7 @@ stm32f7 END ROM_OFF=0x08000000 RAM_OFF=0x20010000 CPU=cortex-m7 FPU=hard-fpv5-sp
stm32l0 END ROM_OFF=0x08000000 RAM_OFF=0x20000000 CPU=cortex-m0plus FPU=soft
stm32l1 END ROM_OFF=0x08000000 RAM_OFF=0x20000000 CPU=cortex-m3 FPU=soft
stm32l4 END ROM_OFF=0x08000000 RAM_OFF=0x20000000 RAM2_OFF=0x10000000 RAM3_OFF=0x20040000 CPU=cortex-m4 FPU=hard-fpv4-sp-d16
stm32u5 END ROM_OFF=0x08000000 RAM_OFF=0x20000000 RAM2_OFF=0x20030000 RAM3_OFF=0x20040000 RAM4_OFF=0x28000000 CPU=cortex-m33 FPU=hard-fpv5-sp-d16
stm32u5 END ROM_OFF=0x08000000 RAM_OFF=0x20000000 SRAM4=16K SRAM4_OFF=0x28000000 CPU=cortex-m33 FPU=hard-fpv5-sp-d16
stm32g0 END ROM_OFF=0x08000000 RAM_OFF=0x20000000 CPU=cortex-m0plus FPU=soft
stm32g4 END ROM_OFF=0x08000000 RAM_OFF=0x20000000 CPU=cortex-m4 FPU=hard-fpv4-sp-d16
stm32h7 END ROM_OFF=0x08000000 ROM2_OFF=0x08100000 RAM_OFF=0x24000000 RAM2_OFF=0x30000000 RAM3_OFF=0x30020000 RAM4_OFF=0x30040000 RAM5_OFF=0x38000000 CCM_OFF=0x20000000 CPU=cortex-m7 FPU=hard-fpv5-d16

View File

@@ -58,6 +58,26 @@ void scb_reset_system(void)
while (1);
}
void scb_set_sleepdeep(void)
{
SCB_SCR |= SCB_SCR_SLEEPDEEP;
}
void scb_clear_sleepdeep(void)
{
SCB_SCR &= ~SCB_SCR_SLEEPDEEP;
}
void scb_set_sleeponexit(void)
{
SCB_SCR |= SCB_SCR_SLEEPONEXIT;
}
void scb_clear_sleeponexit(void)
{
SCB_SCR &= ~SCB_SCR_SLEEPONEXIT;
}
/* Those are defined only on CM3 or CM4 */
#if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__)
void scb_set_priority_grouping(uint32_t prigroup)

View File

@@ -466,11 +466,15 @@ void can_fifo_release(uint32_t canport, uint8_t fifo)
@param[out] data Unsigned int8[]. Message payload data.
@param[out] timestamp Pointer to store the message timestamp.
Only valid on time triggered CAN. Use NULL to ignore.
@returns int 0-3 depending on how many messages where pending before
releasing the FIFO.
when 0 is returned no message could be retrieved
*/
void can_receive(uint32_t canport, uint8_t fifo, bool release, uint32_t *id,
uint32_t can_receive(uint32_t canport, uint8_t fifo, bool release, uint32_t *id,
bool *ext, bool *rtr, uint8_t *fmi, uint8_t *length,
uint8_t *data, uint16_t *timestamp)
{
uint32_t pending_cnt = can_fifo_pending(canport, fifo);
uint32_t fifo_id = 0;
union {
uint8_t data8[4];
@@ -542,9 +546,28 @@ void can_receive(uint32_t canport, uint8_t fifo, bool release, uint32_t *id,
if (release) {
can_fifo_release(canport, fifo);
}
return pending_cnt;
}
bool can_available_mailbox(uint32_t canport)
{
return CAN_TSR(canport) & (CAN_TSR_TME0 | CAN_TSR_TME1 | CAN_TSR_TME2);
}
/*---------------------------------------------------------------------------*/
/** @brief CAN get number of pending RX messages
@param[in] canport Unsigned int32. CAN block register base @ref can_reg_base.
@param[in] fifo Unsigned int8. FIFO id.
@returns int 1, 2 or 3 if messages are pending in given fifo, 0 otherwise.
*/
uint32_t can_fifo_pending(uint32_t canport, uint8_t fifo)
{
if (fifo == 0) {
return CAN_RF0R(canport) & CAN_RF0R_FMP0_MASK;
} else {
return CAN_RF1R(canport) & CAN_RF1R_FMP1_MASK;
}
}

View File

@@ -477,20 +477,20 @@ adc_set_injected_offset.
@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
@param[in] reg Unsigned int8. Register number (1 ... 4).
@returns Unsigned int32 conversion result.
@returns Signed int32 conversion result.
*/
uint32_t adc_read_injected(uint32_t adc, uint8_t reg)
int32_t adc_read_injected(uint32_t adc, uint8_t reg)
{
switch (reg) {
case 1:
return ADC_JDR1(adc);
return (int16_t)ADC_JDR1(adc);
case 2:
return ADC_JDR2(adc);
return (int16_t)ADC_JDR2(adc);
case 3:
return ADC_JDR3(adc);
return (int16_t)ADC_JDR3(adc);
case 4:
return ADC_JDR4(adc);
return (int16_t)ADC_JDR4(adc);
}
return 0;
}

View File

@@ -43,6 +43,7 @@ OBJS += dac_common_all.o dac_common_v2.o
OBJS += desig_common_all.o desig_common_v1.o
OBJS += dma_common_l1f013.o
OBJS += dmamux.o
OBJS += exti_common_all.o
OBJS += fdcan.o fdcan_common.o
OBJS += flash.o flash_common_all.o flash_common_f.o flash_common_idcache.o
OBJS += gpio_common_all.o gpio_common_f0234.o

View File

@@ -357,7 +357,80 @@ const struct rcc_clock_scale rcc_hse_16mhz_3v3[RCC_CLOCK_3V3_END] = {
},
};
const struct rcc_clock_scale rcc_hse_24mhz_3v3[RCC_CLOCK_3V3_END] = {
{ /* 24MHz */
.pllm = 2,
.plln = 8,
.pllp = 0,
.pllq = 2,
.pllr = 4,
.pll_source = RCC_PLLCFGR_PLLSRC_HSE,
.hpre = RCC_CFGR_HPRE_NODIV,
.ppre1 = RCC_CFGR_PPREx_NODIV,
.ppre2 = RCC_CFGR_PPREx_NODIV,
.vos_scale = PWR_SCALE2,
.boost = false,
.flash_config = FLASH_ACR_DCEN | FLASH_ACR_ICEN,
.flash_waitstates = 1,
.ahb_frequency = 24e6,
.apb1_frequency = 24e6,
.apb2_frequency = 24e6,
},
{ /* 48MHz */
.pllm = 2,
.plln = 8,
.pllp = 0,
.pllq = 2,
.pllr = 2,
.pll_source = RCC_PLLCFGR_PLLSRC_HSE,
.hpre = RCC_CFGR_HPRE_NODIV,
.ppre1 = RCC_CFGR_PPREx_NODIV,
.ppre2 = RCC_CFGR_PPREx_NODIV,
.vos_scale = PWR_SCALE1,
.boost = false,
.flash_config = FLASH_ACR_DCEN | FLASH_ACR_ICEN,
.flash_waitstates = 1,
.ahb_frequency = 48e6,
.apb1_frequency = 48e6,
.apb2_frequency = 48e6,
},
{ /* 96MHz */
.pllm = 2,
.plln = 16,
.pllp = 0,
.pllq = 4,
.pllr = 2,
.pll_source = RCC_PLLCFGR_PLLSRC_HSE,
.hpre = RCC_CFGR_HPRE_NODIV,
.ppre1 = RCC_CFGR_PPREx_NODIV,
.ppre2 = RCC_CFGR_PPREx_NODIV,
.vos_scale = PWR_SCALE1,
.boost = false,
.flash_config = FLASH_ACR_DCEN | FLASH_ACR_ICEN,
.flash_waitstates = 3,
.ahb_frequency = 96e6,
.apb1_frequency = 96e6,
.apb2_frequency = 96e6,
},
{ /* 170MHz */
.pllm = 6,
.plln = 85,
.pllp = 0,
.pllq = 0, /* USB requires CRS at this speed. */
.pllr = 2,
.pll_source = RCC_PLLCFGR_PLLSRC_HSE,
.hpre = RCC_CFGR_HPRE_NODIV,
.ppre1 = RCC_CFGR_PPREx_NODIV,
.ppre2 = RCC_CFGR_PPREx_NODIV,
.vos_scale = PWR_SCALE1,
.boost = true,
.flash_config = FLASH_ACR_DCEN | FLASH_ACR_ICEN,
.flash_waitstates = 4,
.ahb_frequency = 170e6,
.apb1_frequency = 170e6,
.apb2_frequency = 170e6,
},
};
void rcc_osc_ready_int_clear(enum rcc_osc osc)
{

View File

@@ -72,4 +72,38 @@ void pwr_enable_backup_domain_write_protect(void)
PWR_CR1 &= ~PWR_CR1_DBP;
}
/** Enable Low Power Run
*
* This enables low power run mode. The clock frequency is limited to 2 MHz in this mode
* and must be set before entering low power run mode.
*/
void pwr_enable_low_power_run(void)
{
PWR_CR1 |= PWR_CR1_LPR;
}
/** Disable Low Power Run
*
* This disables low power run mode
*/
void pwr_disable_low_power_run(void)
{
PWR_CR1 &= ~PWR_CR1_LPR;
}
/** @brief Select the low power mode used in deep sleep.
*
* Set which power mode is entered when the processor enters deep sleep.
*
* @param[in] lpms low power mode @ref pwr_cr1_lpms
*/
void pwr_set_low_power_mode_selection(uint32_t lpms)
{
uint32_t reg32;
reg32 = PWR_CR1;
reg32 &= ~(PWR_CR1_LPMS_MASK << PWR_CR1_LPMS_SHIFT);
PWR_CR1 = (reg32 | (lpms << PWR_CR1_LPMS_SHIFT));
}
/**@}*/

View File

@@ -63,7 +63,7 @@ void dwc_ep_setup(usbd_device *const usbd_dev, const uint8_t addr, const uint8_t
}
REBASE(OTG_DIEPTSIZ0) = (max_size & OTG_DIEPSIZ0_XFRSIZ_MASK);
REBASE(OTG_DIEPCTL0) |= OTG_DIEPCTL0_EPENA | OTG_DIEPCTL0_SNAK;
REBASE(OTG_DIEPCTL0) |= OTG_DIEPCTL0_SNAK | OTG_DIEPCTL0_USBAEP;
#endif
/* Configure OUT part. */
@@ -104,7 +104,7 @@ void dwc_ep_setup(usbd_device *const usbd_dev, const uint8_t addr, const uint8_t
(type << OTG_DIEPCTLX_EPTYP_SHIFT) | OTG_DIEPCTLX_SD0PID | (ep << OTG_DIEPCTLX_TXFNUM_SHIFT);
#else
REBASE(OTG_DIEPTSIZ(ep)) = max_size & OTG_DIEPSIZ0_XFRSIZ_MASK;
REBASE(OTG_DIEPCTL(ep)) |= OTG_DIEPCTL0_EPENA | OTG_DIEPCTL0_SNAK | (type << OTG_DIEPCTLX_EPTYP_SHIFT) |
REBASE(OTG_DIEPCTL(ep)) |= OTG_DIEPCTL0_SNAK | (type << OTG_DIEPCTLX_EPTYP_SHIFT) |
OTG_DIEPCTL0_USBAEP | OTG_DIEPCTLX_SD0PID | (ep << OTG_DIEPCTLX_TXFNUM_SHIFT) |
(max_size & OTG_DIEPCTLX_MPSIZ_MASK);
#endif
@@ -240,7 +240,7 @@ uint16_t dwc_ep_write_packet(usbd_device *const usbd_dev, const uint8_t addr, co
const uint32_t *buf32 = buf;
/* Copy buffer to endpoint FIFO, note - memcpy does not work.
* ARMv7M supports non-word-aligned accesses, ARMv6M does not. */
#if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__)
#if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__) || defined(__ARM_ARCH_8M_MAIN__)
for (size_t i = 0; i < len; i += 4) {
REBASE(OTG_FIFO(ep)) = *buf32++;
}
@@ -293,7 +293,7 @@ uint16_t dwc_ep_read_packet(usbd_device *usbd_dev, uint8_t addr, void *buf, uint
int i = 0;
uint32_t *buf32 = buf;
/* ARMv7M supports non-word-aligned accesses, ARMv6M does not. */
#if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__)
#if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__) || defined(__ARM_ARCH_8M_MAIN__)
for (i = len; i >= 4; i -= 4) {
*buf32++ = REBASE(OTG_FIFO(0));
usbd_dev->rxbcnt -= 4;