mirror of
https://github.com/micropython/micropython.git
synced 2025-12-16 01:40:14 +01:00
This commit adapts the stm32 port to allow switching from STM USB stack to
TinyUSB stack.
Using TinyUSB improves consistancy with other MicroPython ports and brings
in the ability to use the runtime USB definition support recently added to
other TinyUSB based ports.
By default the existing STM USB stack is used. TinyUSB can be enabled in a
board configuration with:
#define MICROPY_HW_TINYUSB_STACK (1)
Or, it can be enabled from the command line with:
make -C ports/stm32 CFLAGS_EXTRA='-DMICROPY_HW_TINYUSB_STACK=1'
Signed-off-by: Andrew Leech <andrew@alelec.net>
225 lines
7.6 KiB
C
225 lines
7.6 KiB
C
#include <string.h>
|
|
|
|
#include "py/runtime.h"
|
|
#include "py/stream.h"
|
|
#include "py/mperrno.h"
|
|
#include "py/mphal.h"
|
|
#include "extmod/misc.h"
|
|
#include "usb.h"
|
|
#include "uart.h"
|
|
|
|
#if MICROPY_HW_TINYUSB_STACK
|
|
#include "shared/tinyusb/mp_usbd_cdc.h"
|
|
|
|
#ifndef MICROPY_HW_STDIN_BUFFER_LEN
|
|
#define MICROPY_HW_STDIN_BUFFER_LEN 512
|
|
#endif
|
|
|
|
static uint8_t stdin_ringbuf_array[MICROPY_HW_STDIN_BUFFER_LEN];
|
|
ringbuf_t stdin_ringbuf = { stdin_ringbuf_array, sizeof(stdin_ringbuf_array), 0, 0 };
|
|
#endif
|
|
|
|
// this table converts from HAL_StatusTypeDef to POSIX errno
|
|
const byte mp_hal_status_to_errno_table[4] = {
|
|
[HAL_OK] = 0,
|
|
[HAL_ERROR] = MP_EIO,
|
|
[HAL_BUSY] = MP_EBUSY,
|
|
[HAL_TIMEOUT] = MP_ETIMEDOUT,
|
|
};
|
|
|
|
#if defined(STM32H5)
|
|
uint8_t mp_hal_unique_id_address[12];
|
|
#endif
|
|
|
|
MP_NORETURN void mp_hal_raise(HAL_StatusTypeDef status) {
|
|
mp_raise_OSError(mp_hal_status_to_errno_table[status]);
|
|
}
|
|
|
|
MP_WEAK uintptr_t mp_hal_stdio_poll(uintptr_t poll_flags) {
|
|
uintptr_t ret = 0;
|
|
#if MICROPY_HW_USB_CDC && MICROPY_HW_TINYUSB_STACK
|
|
ret |= mp_usbd_cdc_poll_interfaces(poll_flags);
|
|
#endif
|
|
if (MP_STATE_PORT(pyb_stdio_uart) != NULL) {
|
|
mp_obj_t pyb_stdio_uart = MP_OBJ_FROM_PTR(MP_STATE_PORT(pyb_stdio_uart));
|
|
int errcode;
|
|
const mp_stream_p_t *stream_p = mp_get_stream(pyb_stdio_uart);
|
|
ret = stream_p->ioctl(pyb_stdio_uart, MP_STREAM_POLL, poll_flags, &errcode);
|
|
}
|
|
return ret | mp_os_dupterm_poll(poll_flags);
|
|
}
|
|
|
|
MP_WEAK int mp_hal_stdin_rx_chr(void) {
|
|
for (;;) {
|
|
#if 0
|
|
#ifdef USE_HOST_MODE
|
|
pyb_usb_host_process();
|
|
int c = pyb_usb_host_get_keyboard();
|
|
if (c != 0) {
|
|
return c;
|
|
}
|
|
#endif
|
|
#endif
|
|
if (MP_STATE_PORT(pyb_stdio_uart) != NULL && uart_rx_any(MP_STATE_PORT(pyb_stdio_uart))) {
|
|
return uart_rx_char(MP_STATE_PORT(pyb_stdio_uart));
|
|
}
|
|
int dupterm_c = mp_os_dupterm_rx_chr();
|
|
if (dupterm_c >= 0) {
|
|
return dupterm_c;
|
|
}
|
|
#if MICROPY_HW_USB_CDC && MICROPY_HW_TINYUSB_STACK
|
|
mp_usbd_cdc_poll_interfaces(0);
|
|
int c = ringbuf_get(&stdin_ringbuf);
|
|
if (c != -1) {
|
|
return c;
|
|
}
|
|
#endif
|
|
MICROPY_EVENT_POLL_HOOK
|
|
}
|
|
}
|
|
|
|
MP_WEAK mp_uint_t mp_hal_stdout_tx_strn(const char *str, size_t len) {
|
|
mp_uint_t ret = len;
|
|
bool did_write = false;
|
|
if (MP_STATE_PORT(pyb_stdio_uart) != NULL) {
|
|
uart_tx_strn(MP_STATE_PORT(pyb_stdio_uart), str, len);
|
|
did_write = true;
|
|
}
|
|
#if MICROPY_HW_USB_CDC && MICROPY_HW_TINYUSB_STACK
|
|
mp_uint_t cdc_res = mp_usbd_cdc_tx_strn(str, len);
|
|
if (cdc_res > 0) {
|
|
did_write = true;
|
|
ret = MIN(cdc_res, ret);
|
|
}
|
|
#endif
|
|
#if 0 && defined(USE_HOST_MODE) && MICROPY_HW_HAS_LCD
|
|
lcd_print_strn(str, len);
|
|
#endif
|
|
int dupterm_res = mp_os_dupterm_tx_strn(str, len);
|
|
if (dupterm_res >= 0) {
|
|
did_write = true;
|
|
ret = MIN((mp_uint_t)dupterm_res, ret);
|
|
}
|
|
return did_write ? ret : 0;
|
|
}
|
|
|
|
#if __CORTEX_M >= 0x03
|
|
void mp_hal_ticks_cpu_enable(void) {
|
|
if (!(DWT->CTRL & DWT_CTRL_CYCCNTENA_Msk)) {
|
|
CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
|
|
#if defined(__CORTEX_M) && __CORTEX_M == 7
|
|
// on Cortex-M7 we must unlock the DWT before writing to its registers
|
|
DWT->LAR = 0xc5acce55;
|
|
#endif
|
|
DWT->CYCCNT = 0;
|
|
DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
void mp_hal_gpio_clock_enable(GPIO_TypeDef *gpio) {
|
|
#if defined(STM32L476xx) || defined(STM32L496xx) || defined(STM32U5)
|
|
if (gpio == GPIOG) {
|
|
// Port G pins 2 thru 15 are powered using VddIO2 on these MCUs.
|
|
HAL_PWREx_EnableVddIO2();
|
|
}
|
|
#endif
|
|
|
|
// This logic assumes that all the GPIOx_EN bits are adjacent and ordered in one register
|
|
|
|
#if defined(STM32F0) || defined(STM32L1)
|
|
#define AHBxENR AHBENR
|
|
#define AHBxENR_GPIOAEN_Pos RCC_AHBENR_GPIOAEN_Pos
|
|
#elif defined(STM32F4) || defined(STM32F7)
|
|
#define AHBxENR AHB1ENR
|
|
#define AHBxENR_GPIOAEN_Pos RCC_AHB1ENR_GPIOAEN_Pos
|
|
#elif defined(STM32H7) || defined(STM32N6)
|
|
#define AHBxENR AHB4ENR
|
|
#define AHBxENR_GPIOAEN_Pos RCC_AHB4ENR_GPIOAEN_Pos
|
|
#elif defined(STM32L0)
|
|
#define AHBxENR IOPENR
|
|
#define AHBxENR_GPIOAEN_Pos RCC_IOPENR_IOPAEN_Pos
|
|
#elif defined(STM32G0)
|
|
#define AHBxENR IOPENR
|
|
#define AHBxENR_GPIOAEN_Pos RCC_IOPENR_GPIOAEN_Pos
|
|
#elif defined(STM32G4) || defined(STM32H5) || defined(STM32L4) || defined(STM32WB) || defined(STM32WL)
|
|
#define AHBxENR AHB2ENR
|
|
#define AHBxENR_GPIOAEN_Pos RCC_AHB2ENR_GPIOAEN_Pos
|
|
#elif defined(STM32U5)
|
|
#define AHBxENR AHB2ENR1
|
|
#define AHBxENR_GPIOAEN_Pos RCC_AHB2ENR1_GPIOAEN_Pos
|
|
#endif
|
|
|
|
uint32_t gpio_idx = ((uint32_t)gpio - GPIOA_BASE) / (GPIOB_BASE - GPIOA_BASE);
|
|
RCC->AHBxENR |= 1 << (AHBxENR_GPIOAEN_Pos + gpio_idx);
|
|
volatile uint32_t tmp = RCC->AHBxENR; // Delay after enabling clock
|
|
(void)tmp;
|
|
}
|
|
|
|
void mp_hal_pin_config(mp_hal_pin_obj_t pin_obj, uint32_t mode, uint32_t pull, uint32_t alt) {
|
|
GPIO_TypeDef *gpio = pin_obj->gpio;
|
|
uint32_t pin = pin_obj->pin;
|
|
mp_hal_gpio_clock_enable(gpio);
|
|
if (mode == MP_HAL_PIN_MODE_ALT || mode == MP_HAL_PIN_MODE_ALT_OPEN_DRAIN) {
|
|
// To avoid any I/O glitches, make sure a valid alternate function is set in
|
|
// AFR first before switching the pin mode. When switching from AF to INPUT or
|
|
// OUTPUT, the AF in AFR will remain valid up until the pin mode is switched.
|
|
gpio->AFR[pin >> 3] = (gpio->AFR[pin >> 3] & ~(15 << (4 * (pin & 7)))) | (alt << (4 * (pin & 7)));
|
|
}
|
|
gpio->MODER = (gpio->MODER & ~(3 << (2 * pin))) | ((mode & 3) << (2 * pin));
|
|
#if defined(GPIO_ASCR_ASC0)
|
|
// The L4 has a special analog switch to connect the GPIO to the ADC
|
|
gpio->OTYPER = (gpio->OTYPER & ~(1 << pin)) | (((mode >> 2) & 1) << pin);
|
|
gpio->ASCR = (gpio->ASCR & ~(1 << pin)) | ((mode >> 3) & 1) << pin;
|
|
#else
|
|
gpio->OTYPER = (gpio->OTYPER & ~(1 << pin)) | ((mode >> 2) << pin);
|
|
#endif
|
|
gpio->OSPEEDR = (gpio->OSPEEDR & ~(3 << (2 * pin))) | (2 << (2 * pin)); // full speed
|
|
gpio->PUPDR = (gpio->PUPDR & ~(3 << (2 * pin))) | (pull << (2 * pin));
|
|
}
|
|
|
|
bool mp_hal_pin_config_alt(mp_hal_pin_obj_t pin, uint32_t mode, uint32_t pull, uint8_t fn, uint8_t unit) {
|
|
const pin_af_obj_t *af = pin_find_af(pin, fn, unit);
|
|
if (af == NULL) {
|
|
return false;
|
|
}
|
|
mp_hal_pin_config(pin, mode, pull, af->idx);
|
|
return true;
|
|
}
|
|
|
|
void mp_hal_pin_config_speed(mp_hal_pin_obj_t pin_obj, uint32_t speed) {
|
|
GPIO_TypeDef *gpio = pin_obj->gpio;
|
|
uint32_t pin = pin_obj->pin;
|
|
gpio->OSPEEDR = (gpio->OSPEEDR & ~(3 << (2 * pin))) | (speed << (2 * pin));
|
|
}
|
|
|
|
/*******************************************************************************/
|
|
// MAC address
|
|
|
|
// Generate a random locally administered MAC address (LAA)
|
|
void mp_hal_generate_laa_mac(int idx, uint8_t buf[6]) {
|
|
uint8_t *id = (uint8_t *)MP_HAL_UNIQUE_ID_ADDRESS;
|
|
buf[0] = 0x02; // LAA range
|
|
buf[1] = (id[11] << 4) | (id[10] & 0xf);
|
|
buf[2] = (id[9] << 4) | (id[8] & 0xf);
|
|
buf[3] = (id[7] << 4) | (id[6] & 0xf);
|
|
buf[4] = id[2];
|
|
buf[5] = (id[0] << 2) | idx;
|
|
}
|
|
|
|
// A board can override this if needed
|
|
MP_WEAK void mp_hal_get_mac(int idx, uint8_t buf[6]) {
|
|
mp_hal_generate_laa_mac(idx, buf);
|
|
}
|
|
|
|
void mp_hal_get_mac_ascii(int idx, size_t chr_off, size_t chr_len, char *dest) {
|
|
static const char hexchr[16] = "0123456789ABCDEF";
|
|
uint8_t mac[6];
|
|
mp_hal_get_mac(idx, mac);
|
|
for (; chr_len; ++chr_off, --chr_len) {
|
|
*dest++ = hexchr[mac[chr_off >> 1] >> (4 * (1 - (chr_off & 1))) & 0xf];
|
|
}
|
|
}
|
|
|
|
MP_REGISTER_ROOT_POINTER(struct _machine_uart_obj_t *pyb_stdio_uart);
|