mirror of
https://github.com/cesanta/mongoose.git
synced 2026-10-28 12:30:58 +00:00
166 lines
7.1 KiB
C
166 lines
7.1 KiB
C
// Copyright (c) 2013-2026 Cesanta Software Limited
|
|
// Datasheet: RM0522, devboard manual: UM3616
|
|
// https://www.st.com/resource/en/reference_manual/rm0522-stm32c5-series-armbased-32bit-mcus-stmicroelectronics.pdf
|
|
// https://www.st.com/resource/en/user_manual/um3616-stm32c5-nucleo144-board-mb2310-stmicroelectronics.pdf
|
|
|
|
#pragma once
|
|
|
|
#include <stm32c5xx.h>
|
|
|
|
#include <stdbool.h>
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
|
|
extern bool hal_timer_expired(volatile uint64_t *t, uint64_t prd, uint64_t now);
|
|
extern uint64_t hal_get_tick(void);
|
|
extern size_t hal_ram_free(void);
|
|
extern size_t hal_ram_used(void);
|
|
extern uint32_t SystemCoreClock;
|
|
|
|
#define BIT(x) (1UL << (x))
|
|
#define CLRSET(reg, clear, set) ((reg) = ((reg) & ~(clear)) | (set))
|
|
#define PIN(bank, num) ((((bank) - 'A') << 8) | (num))
|
|
#define PINNO(pin) (pin & 255)
|
|
#define PINBANK(pin) (pin >> 8)
|
|
|
|
// Ethernet RMII pins and their alternate functions. UM3616 7.11, Table 9
|
|
#define HAL_ETH_PINS \
|
|
{PIN('A', 1), 10}, /* REF_CLK */ \
|
|
{PIN('C', 1), 10}, /* MDC */ \
|
|
{PIN('E', 12), 10}, /* MDIO */ \
|
|
{PIN('D', 1), 10}, /* CRS_DV */ \
|
|
{PIN('C', 4), 12}, /* RXD0 */ \
|
|
{PIN('C', 5), 13}, /* RXD1 */ \
|
|
{PIN('G', 11), 10}, /* TX_EN */ \
|
|
{PIN('G', 13), 10}, /* TXD0 */ \
|
|
{PIN('G', 12), 10} /* TXD1 */
|
|
|
|
// System clock (9.4.2, 9.4.8). HSI runs at 144 MHz, the maximum system clock:
|
|
// SYSCLK = HSIS, no PLL. hclk = SYSCLK, APB clocks = hclk. After reset, the
|
|
// system runs on HSIDIV3, 48 MHz. Flash latency for 144 MHz: 6.3.6, Table 20
|
|
#define SYS_FREQUENCY 144000000
|
|
#define AHB_FREQUENCY SYS_FREQUENCY
|
|
#define APB2_FREQUENCY AHB_FREQUENCY
|
|
#define APB1_FREQUENCY AHB_FREQUENCY
|
|
#define HAL_FLASH_LATENCY (4 | FLASH_ACR_WRHIGHFREQ_1) // 4 WS, WRHIGHFREQ 2
|
|
|
|
enum { HAL_GPIO_MODE_INPUT, HAL_GPIO_MODE_OUTPUT, HAL_GPIO_MODE_AF, HAL_GPIO_MODE_ANALOG };
|
|
enum { HAL_GPIO_OTYPE_PUSH_PULL, HAL_GPIO_OTYPE_OPEN_DRAIN };
|
|
enum { HAL_GPIO_SPEED_LOW, HAL_GPIO_SPEED_MEDIUM, HAL_GPIO_SPEED_HIGH, HAL_GPIO_SPEED_INSANE };
|
|
enum { HAL_GPIO_PULL_NONE, HAL_GPIO_PULL_UP, HAL_GPIO_PULL_DOWN };
|
|
|
|
#define HAL_GPIO(N) ((GPIO_TypeDef *) (GPIOA_BASE + 0x400 * (N)))
|
|
|
|
static GPIO_TypeDef *hal_gpio_bank(uint16_t pin) {
|
|
return HAL_GPIO(PINBANK(pin));
|
|
}
|
|
static inline void hal_gpio_toggle(uint16_t pin) {
|
|
GPIO_TypeDef *gpio = hal_gpio_bank(pin);
|
|
uint32_t mask = BIT(PINNO(pin));
|
|
gpio->BSRR = mask << (gpio->ODR & mask ? 16 : 0);
|
|
}
|
|
static inline int hal_gpio_read(uint16_t pin) {
|
|
return hal_gpio_bank(pin)->IDR & BIT(PINNO(pin)) ? 1 : 0;
|
|
}
|
|
static inline void hal_gpio_write(uint16_t pin, bool val) {
|
|
GPIO_TypeDef *gpio = hal_gpio_bank(pin);
|
|
gpio->BSRR = BIT(PINNO(pin)) << (val ? 0 : 16);
|
|
}
|
|
static inline void hal_gpio_init(uint16_t pin, uint8_t mode, uint8_t type,
|
|
uint8_t speed, uint8_t pull, uint8_t af) {
|
|
GPIO_TypeDef *gpio = hal_gpio_bank(pin);
|
|
uint8_t n = (uint8_t) (PINNO(pin));
|
|
RCC->AHB2ENR |= BIT(PINBANK(pin)); // Enable GPIO clock
|
|
CLRSET(gpio->OTYPER, 1UL << n, ((uint32_t) type) << n);
|
|
CLRSET(gpio->OSPEEDR, 3UL << (n * 2), ((uint32_t) speed) << (n * 2));
|
|
CLRSET(gpio->PUPDR, 3UL << (n * 2), ((uint32_t) pull) << (n * 2));
|
|
CLRSET(gpio->AFR[n >> 3], 15UL << ((n & 7) * 4),
|
|
((uint32_t) af) << ((n & 7) * 4));
|
|
CLRSET(gpio->MODER, 3UL << (n * 2), ((uint32_t) mode) << (n * 2));
|
|
}
|
|
static inline void hal_gpio_input(uint16_t pin) {
|
|
hal_gpio_init(pin, HAL_GPIO_MODE_INPUT, HAL_GPIO_OTYPE_PUSH_PULL, HAL_GPIO_SPEED_HIGH,
|
|
HAL_GPIO_PULL_NONE, 0);
|
|
}
|
|
static inline void hal_gpio_output(uint16_t pin) {
|
|
hal_gpio_init(pin, HAL_GPIO_MODE_OUTPUT, HAL_GPIO_OTYPE_PUSH_PULL, HAL_GPIO_SPEED_HIGH,
|
|
HAL_GPIO_PULL_NONE, 0);
|
|
}
|
|
|
|
// USART1 kernel clock defaults to pclk2 (APB2), USART2,3 default to pclk1
|
|
// (APB1), see RCC_CCIPR1
|
|
static inline void hal_uart_init(USART_TypeDef *uart, uint16_t tx,
|
|
uint16_t rx, unsigned long baud) {
|
|
uint8_t af = 7; // Alternate function
|
|
uint32_t freq = 0; // Bus frequency. UART1 is on APB2, rest on APB1
|
|
|
|
if (uart == USART1) freq = APB2_FREQUENCY, RCC->APB2ENR |= RCC_APB2ENR_USART1EN;
|
|
if (uart == USART2) freq = APB1_FREQUENCY, RCC->APB1LENR |= RCC_APB1LENR_USART2EN;
|
|
if (uart == USART3) freq = APB1_FREQUENCY, RCC->APB1LENR |= RCC_APB1LENR_USART3EN;
|
|
|
|
hal_gpio_init(tx, HAL_GPIO_MODE_AF, HAL_GPIO_OTYPE_PUSH_PULL, HAL_GPIO_SPEED_HIGH, 0, af);
|
|
hal_gpio_init(rx, HAL_GPIO_MODE_AF, HAL_GPIO_OTYPE_PUSH_PULL, HAL_GPIO_SPEED_HIGH, 0, af);
|
|
uart->CR1 = 0; // Disable this UART
|
|
uart->BRR = freq / baud; // Set baud rate
|
|
uart->CR1 = BIT(0) | BIT(2) | BIT(3); // Set UE, RE, TE
|
|
}
|
|
static inline void hal_uart_write_byte(USART_TypeDef *uart, uint8_t byte) {
|
|
uart->TDR = byte;
|
|
while ((uart->ISR & USART_ISR_TXE_TXFNF) == 0) (void) 0;
|
|
}
|
|
static inline void hal_uart_write_buf(USART_TypeDef *uart, char *buf, size_t len) {
|
|
while (len-- > 0) hal_uart_write_byte(uart, *(uint8_t *) buf++);
|
|
}
|
|
static inline int hal_uart_read_ready(USART_TypeDef *uart) {
|
|
return uart->ISR & BIT(5); // If RXNE bit is set, data is ready
|
|
}
|
|
static inline uint8_t hal_uart_read_byte(USART_TypeDef *uart) {
|
|
return (uint8_t) (uart->RDR & 255);
|
|
}
|
|
|
|
// RNG clock (rng_clk) is CK48, which is disabled after reset. Use HSIDIV3,
|
|
// 48 MHz. It stays enabled after the system clock switches to HSIS
|
|
static inline void hal_rng_init(void) {
|
|
CLRSET(RCC->CCIPR2, RCC_CCIPR2_CK48SEL_Msk, RCC_CCIPR2_CK48SEL_1);
|
|
RCC->AHB2ENR |= RCC_AHB2ENR_RNGEN; // Enable RNG AHB clock
|
|
RNG->CR |= RNG_CR_RNGEN; // Enable RNG
|
|
}
|
|
|
|
static inline uint32_t hal_rng_read(void) {
|
|
while ((RNG->SR & RNG_SR_DRDY) == 0) (void) 0;
|
|
return RNG->DR;
|
|
}
|
|
|
|
static inline void hal_ethernet_init(void) {
|
|
// Initialise Ethernet. Enable MAC GPIO pins, see UM3616 Table 9
|
|
uint16_t pins[][2] = {HAL_ETH_PINS};
|
|
for (size_t i = 0; i < sizeof(pins) / sizeof(pins[0]); i++) {
|
|
hal_gpio_init(pins[i][0], HAL_GPIO_MODE_AF, HAL_GPIO_OTYPE_PUSH_PULL, HAL_GPIO_SPEED_INSANE,
|
|
HAL_GPIO_PULL_NONE, (uint8_t) pins[i][1]);
|
|
}
|
|
NVIC_EnableIRQ(ETH1_IRQn); // Setup Ethernet IRQ handler
|
|
RCC->APB3ENR |= RCC_APB3ENR_SBSEN; // Enable SBS clock
|
|
CLRSET(SBS->PMCR, SBS_PMCR_ETH1_SEL_PHY_Msk, SBS_PMCR_ETH1_SEL_PHY_2); // RMII
|
|
RCC->AHB1ENR |= RCC_AHB1ENR_ETH1CKEN | RCC_AHB1ENR_ETH1EN |
|
|
RCC_AHB1ENR_ETH1TXEN | RCC_AHB1ENR_ETH1RXEN;
|
|
}
|
|
|
|
static inline void hal_clock_init(void) {
|
|
CLRSET(FLASH->ACR, FLASH_ACR_LATENCY_Msk | FLASH_ACR_WRHIGHFREQ_Msk,
|
|
HAL_FLASH_LATENCY);
|
|
while ((FLASH->ACR & FLASH_ACR_LATENCY_Msk) != (HAL_FLASH_LATENCY & 15)) (void) 0;
|
|
RCC->CR1 |= RCC_CR1_HSISON; // Enable HSIS, 144 MHz
|
|
while ((RCC->CR1 & RCC_CR1_HSISRDY) == 0) (void) 0; // Wait until ready
|
|
CLRSET(RCC->CFGR1, RCC_CFGR1_SW_Msk, RCC_CFGR1_SW_0); // SYSCLK = HSIS
|
|
while ((RCC->CFGR1 & RCC_CFGR1_SWS_Msk) != RCC_CFGR1_SWS_0) (void) 0;
|
|
SystemCoreClock = SYS_FREQUENCY; // Update SystemCoreClock global var
|
|
SysTick_Config(SystemCoreClock / 1000); // Sys tick every 1ms
|
|
}
|
|
|
|
static inline void hal_system_init(void) {
|
|
SCB->CPACR |= ((3UL << 10 * 2) | (3UL << 11 * 2)); // Enable FPU
|
|
__DSB();
|
|
__ISB();
|
|
}
|