integrate picolibc and its stdio
This commit is contained in:
parent
77eda9fcb7
commit
8bcec75693
|
@ -0,0 +1,4 @@
|
|||
#pragma once
|
||||
#include <stdint.h>
|
||||
|
||||
void iob_init(uint32_t usart);
|
|
@ -0,0 +1,5 @@
|
|||
#pragma once
|
||||
|
||||
int watchdog_init(void);
|
||||
void watchdog_fini(void);
|
||||
void watchdog_refresh(void);
|
|
@ -0,0 +1,62 @@
|
|||
#include <stdio.h>
|
||||
#include <libopencm3/cm3/scb.h>
|
||||
#include <libopencm3/cm3/nvic.h>
|
||||
#ifndef STM32F1
|
||||
#include <libopencm3/stm32/syscfg.h>
|
||||
#endif
|
||||
|
||||
struct hardfault_args {
|
||||
unsigned long r0;
|
||||
unsigned long r1;
|
||||
unsigned long r2;
|
||||
unsigned long r3;
|
||||
unsigned long r12;
|
||||
unsigned long lr;
|
||||
unsigned long pc;
|
||||
unsigned long psr;
|
||||
};
|
||||
|
||||
extern void hard_fault_handler_c(struct hardfault_args *args);
|
||||
|
||||
__attribute__((naked))
|
||||
void hard_fault_handler(void)
|
||||
{
|
||||
__asm( ".syntax unified\n"
|
||||
"movs r0, #4 \n"
|
||||
"mov r1, lr \n"
|
||||
"tst r0, r1 \n"
|
||||
"beq _MSP \n"
|
||||
"mrs r0, psp \n"
|
||||
"b _CHAND \n"
|
||||
"_MSP: \n"
|
||||
"mrs r0, msp \n"
|
||||
"_CHAND: \n"
|
||||
"b hard_fault_handler_c\n"
|
||||
".syntax divided\n");
|
||||
}
|
||||
|
||||
void hard_fault_handler_c(struct hardfault_args *args)
|
||||
{
|
||||
//usart_stop(1, 0);
|
||||
fprintf(stderr, "HARDFAULT\r\n");
|
||||
fprintf(stderr, "R0=%08lx, R1=%08lx, R2=%08lx, R3=%08lx, R12=%08lx\r\n",
|
||||
args->r0, args->r1, args->r2, args->r3, args->r12);
|
||||
fprintf(stderr, "LR[R14]=%08lx, PC[R15]=%08lx, PSR=%08lx\r\n",
|
||||
args->lr, args->pc, args->psr);
|
||||
|
||||
/* we better reset the CPU to avoid getting stuck in some state */
|
||||
scb_reset_system();
|
||||
}
|
||||
|
||||
void nmi_handler(void)
|
||||
{
|
||||
/* We better do a reset in case we receive a NMI */
|
||||
fprintf(stderr, "NMI\r\n");
|
||||
#ifdef SYSCFG_CFGR2
|
||||
if (SYSCFG_CFGR2 & 0x10) {
|
||||
fprintf(stderr, "PARITY\r\n");
|
||||
SYSCFG_CFGR2 = 0x10;
|
||||
}
|
||||
#endif
|
||||
scb_reset_system();
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
#include <stdio.h>
|
||||
#include <sys/cdefs.h>
|
||||
#include <libopencm3/stm32/usart.h>
|
||||
|
||||
#include <libcommon/iob.h>
|
||||
|
||||
/* picolibc iob implementation for blocking I/O on USART */
|
||||
|
||||
static uint32_t stdio_usart;
|
||||
|
||||
void iob_init(uint32_t usart)
|
||||
{
|
||||
stdio_usart = usart;
|
||||
}
|
||||
|
||||
static int my_putc(char c, FILE *file)
|
||||
{
|
||||
(void) file;
|
||||
usart_send_blocking(stdio_usart, c);
|
||||
return c;
|
||||
}
|
||||
|
||||
static int my_getc(FILE *file)
|
||||
{
|
||||
(void) file;
|
||||
return usart_recv_blocking(stdio_usart);
|
||||
}
|
||||
|
||||
static int my_flush(FILE *file)
|
||||
{
|
||||
(void) file;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static FILE __stdio = FDEV_SETUP_STREAM(my_putc, my_getc, my_flush, _FDEV_SETUP_RW);
|
||||
|
||||
FILE *const __iob[3] = { &__stdio, &__stdio, &__stdio };
|
|
@ -0,0 +1,91 @@
|
|||
#include <stdio.h>
|
||||
#include <sys/cdefs.h>
|
||||
#include <libopencm3/cm3/assert.h>
|
||||
#include <libopencm3/cm3/nvic.h>
|
||||
#include <libopencm3/stm32/usart.h>
|
||||
|
||||
#include <libcommon/iob.h>
|
||||
|
||||
#include <librfn/ringbuf.h>
|
||||
|
||||
/* picolibc iob implementation for non-blocking I/O on USART via ring-buffer */
|
||||
|
||||
static uint32_t stdio_usart;
|
||||
static uint8_t outbuf[1024];
|
||||
static ringbuf_t outring = RINGBUF_VAR_INIT(outbuf, sizeof(outbuf));
|
||||
|
||||
static uint8_t inbuf[256];
|
||||
static ringbuf_t inring = RINGBUF_VAR_INIT(inbuf, sizeof(inbuf));
|
||||
|
||||
void iob_init(uint32_t usart)
|
||||
{
|
||||
cm3_assert(usart == USART2);
|
||||
stdio_usart = usart;
|
||||
|
||||
nvic_enable_irq(NVIC_USART2_IRQ);
|
||||
/* Enable RX non-empty interrupt */
|
||||
USART_CR1(stdio_usart) |= USART_CR1_RXNEIE;
|
||||
}
|
||||
|
||||
/* FIXME: this obviously doesn't work with iob_init() getting passed a dynamic UART */
|
||||
void usart2_isr(void)
|
||||
{
|
||||
if ((USART_CR1(stdio_usart) & USART_CR1_RXNEIE) &&
|
||||
(USART_SR(stdio_usart) & USART_SR_RXNE)) {
|
||||
uint16_t c = usart_recv(stdio_usart);
|
||||
ringbuf_put(&inring, c);
|
||||
}
|
||||
|
||||
if ((USART_CR1(stdio_usart) & USART_CR1_TXEIE) &&
|
||||
(USART_SR(stdio_usart) & USART_SR_TXE)) {
|
||||
int data = ringbuf_get(&outring);
|
||||
if (data == -1) {
|
||||
USART_CR1(stdio_usart) &= ~USART_CR1_TXEIE;
|
||||
} else {
|
||||
usart_send(stdio_usart, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* buffered output to stdout */
|
||||
static int my_stdout_putc(char c, FILE *file)
|
||||
{
|
||||
(void) file;
|
||||
cm3_assert(stdio_usart);
|
||||
ringbuf_put(&outring, c);
|
||||
USART_CR1(stdio_usart) |= USART_CR1_TXEIE;
|
||||
return c;
|
||||
}
|
||||
|
||||
/* unbuffered, blocking output to stderr (e.g. for assert, fault handlers, ...) */
|
||||
static int my_stderr_putc(char c, FILE *file)
|
||||
{
|
||||
(void) file;
|
||||
cm3_assert(stdio_usart);
|
||||
usart_send_blocking(stdio_usart, c);
|
||||
return c;
|
||||
}
|
||||
|
||||
static int my_stdin_getc(FILE *file)
|
||||
{
|
||||
(void) file;
|
||||
int data = ringbuf_get(&inring);
|
||||
|
||||
if (data == -1)
|
||||
return EOF;
|
||||
else
|
||||
return data;
|
||||
}
|
||||
|
||||
static int my_stdout_flush(FILE *file)
|
||||
{
|
||||
(void) file;
|
||||
do { } while (!ringbuf_empty(&outring));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static FILE __stdin = FDEV_SETUP_STREAM(NULL, my_stdin_getc, NULL, _FDEV_SETUP_READ);
|
||||
static FILE __stdout = FDEV_SETUP_STREAM(my_stdout_putc, NULL, my_stdout_flush, _FDEV_SETUP_WRITE);
|
||||
static FILE __stderr = FDEV_SETUP_STREAM(my_stderr_putc, NULL, NULL, _FDEV_SETUP_WRITE);
|
||||
|
||||
FILE *const __iob[3] = { &__stdin, &__stdout, &__stderr };
|
|
@ -0,0 +1,8 @@
|
|||
#include <sys/types.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
pid_t getpid(void) { return 1; }
|
||||
|
||||
int kill(pid_t pid, int sig) { if (pid == 1) _exit(sig << 8); errno = ESRCH; return -1; }
|
|
@ -0,0 +1,70 @@
|
|||
#include <libopencm3/stm32/rcc.h>
|
||||
#include <libopencm3/stm32/wwdg.h>
|
||||
|
||||
#include <libcommon/watchdog.h>
|
||||
|
||||
void watchdog_refresh(void)
|
||||
{
|
||||
/* set to the maximum a 7-bit counter supports */
|
||||
WWDG_CR = 0x7f;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_WATCHDOG
|
||||
void WWDG_IRQHandler(void)
|
||||
{
|
||||
WWDG_ClearFlag();
|
||||
|
||||
/* instead of triggering a reset, we hang in this endless loop to wait
|
||||
* for openocd/gdb attach and investigation of the stack */
|
||||
watchdog_fini();
|
||||
printf("WWDG\r\n");
|
||||
while(1) {}
|
||||
}
|
||||
#endif
|
||||
|
||||
void watchdog_fini(void)
|
||||
{
|
||||
/* documentation claims we cannot stop it. lol. */
|
||||
watchdog_refresh();
|
||||
rcc_periph_clock_disable(RCC_WWDG);
|
||||
}
|
||||
|
||||
int watchdog_init(void)
|
||||
{
|
||||
#ifdef RCC_DBGMCU
|
||||
/* make sure the watchdog stops during JTAG stop */
|
||||
rcc_periph_clock_enable(RCC_DBGMCU);
|
||||
DBGMCU_CR |= DBGMCU_CR_WWDG_STOP
|
||||
#endif
|
||||
|
||||
rcc_periph_clock_enable(RCC_WWDG);
|
||||
|
||||
/* Set WWDG clock to (PCLK1/4096)/8 */
|
||||
/* At 8 MHz PCLK1 this is 244.14 Hz */
|
||||
WWDG_CFR = (WWDG_CFR & ~WWDG_CFR_WDGTB_LSB) | WWDG_CFR_WDGTB_CK_DIV8;
|
||||
|
||||
|
||||
#ifdef DEBUG_WATCHDOG
|
||||
NVIC_InitTypeDef nvic_init = {
|
||||
.NVIC_IRQChannelPriority = 0,
|
||||
.NVIC_IRQChannel = WWDG_IRQn,
|
||||
.NVIC_IRQChannelCmd = ENABLE,
|
||||
};
|
||||
WWDG_EnableIT();
|
||||
NVIC_Init(&nvic_init);
|
||||
#endif
|
||||
|
||||
/* highest possible window value */
|
||||
WWDG_CFR = (WWDG_CFR & WWDG_CFR_WDGTB_LSB) | 0x7f;
|
||||
|
||||
/* this means, that we have 0x80-0x40= 64 cycles of the 214.14Hz
|
||||
* watchdog clock tore-fresh the counter, before it reaches
|
||||
* 0x3F, at which point a reset will be issued to the CPU. If my
|
||||
* calculations are correct, this is 0.262 seconds, i.e.
|
||||
* refreshing every time the systick timer fires (and we return
|
||||
* to the main loop) should be sufficient. */
|
||||
|
||||
WWDG_CR = WWDG_CR_WDGA | 0x7f;
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -12,6 +12,6 @@ OBJS += \
|
|||
vpath %.c $(LIBRFN_DIR)/librfn
|
||||
vpath %.c $(LIBRFN_DIR)/librfn/libopencm3
|
||||
|
||||
CPPFLAGS += -DNDEBUG
|
||||
CPPFLAGS += -DCONFIG_CONSOLE_FROM_ISR=1
|
||||
#CPPFLAGS += -DNDEBUG
|
||||
#CPPFLAGS += -DCONFIG_CONSOLE_FROM_ISR=1
|
||||
CPPFLAGS += -I$(LIBRFN_DIR)/include
|
||||
|
|
|
@ -19,6 +19,8 @@
|
|||
|
||||
BINARY = rfdsatt
|
||||
|
||||
OBJS = attenuator.o board_rfdsatt_4ch.o
|
||||
|
||||
LDSCRIPT = ./stm32f103-openblt.ld
|
||||
|
||||
|
||||
|
@ -36,7 +38,15 @@ OOCD ?= openocd
|
|||
OOCD_INTERFACE ?= stlink-v2
|
||||
OOCD_TARGET ?= stm32f1x
|
||||
|
||||
ARCH_FLAGS += --specs=/usr/lib/picolibc/arm-none-eabi/picolibc.specs
|
||||
|
||||
LIBCOMMON_DIR = ../../libcommon
|
||||
CPPFLAGS += -I$(LIBCOMMON_DIR)/include
|
||||
vpath %.c $(LIBCOMMON_DIR)/src/
|
||||
OBJS += watchdog.o fault.o iob_stm32_nonblocking.o kill.o
|
||||
|
||||
all: elf bin srec
|
||||
|
||||
include ../../mk/librfn.mk
|
||||
include ../rules.mk
|
||||
|
||||
|
|
|
@ -24,9 +24,16 @@
|
|||
#include <libopencm3/cm3/nvic.h>
|
||||
#include <libopencm3/cm3/systick.h>
|
||||
|
||||
#include <libcommon/iob.h>
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "attenuator.h"
|
||||
#include "misc.h"
|
||||
|
||||
extern const struct attenuator_cfg board_att_cfg;
|
||||
extern struct attenuator_state *board_att_st[];
|
||||
|
||||
volatile uint32_t jiffies;
|
||||
|
||||
void sys_tick_handler(void)
|
||||
|
@ -64,12 +71,35 @@ static void clock_setup(void)
|
|||
rcc_periph_clock_enable(RCC_USART2);
|
||||
}
|
||||
|
||||
static void i2c_setup(void)
|
||||
{
|
||||
rcc_periph_clock_enable(RCC_I2C1);
|
||||
|
||||
gpio_set_mode(GPIOB, GPIO_MODE_OUTPUT_50_MHZ,
|
||||
GPIO_CNF_OUTPUT_ALTFN_OPENDRAIN,
|
||||
GPIO_I2C1_SCL | GPIO_I2C1_SDA);
|
||||
|
||||
/* disable before making config changes */
|
||||
i2c_peripheral_disable(I2C1);
|
||||
|
||||
/* APB1 runs at 24 MHz */
|
||||
i2c_set_clock_frequency(I2C1, I2C_CR2_FREQ_24MHZ);
|
||||
|
||||
/* 400 kHz fast mode I2C */
|
||||
//i2c_set_fast_mode(I2C1);
|
||||
|
||||
//...
|
||||
|
||||
i2c_peripheral_enable(I2C1);
|
||||
}
|
||||
|
||||
static void usart_setup(void)
|
||||
{
|
||||
/* USART1: connected to debug header */
|
||||
|
||||
/* Setup GPIO pin GPIO_USART1_TX. */
|
||||
gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_50_MHZ,
|
||||
GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, GPIO_USART1_TX);
|
||||
|
||||
/* Setup UART parameters. */
|
||||
usart_set_baudrate(USART1, 115200);
|
||||
usart_set_databits(USART1, 8);
|
||||
|
@ -77,14 +107,14 @@ static void usart_setup(void)
|
|||
usart_set_mode(USART1, USART_MODE_TX);
|
||||
usart_set_parity(USART1, USART_PARITY_NONE);
|
||||
usart_set_flow_control(USART1, USART_FLOWCONTROL_NONE);
|
||||
|
||||
/* Finally enable the USART. */
|
||||
usart_enable(USART1);
|
||||
|
||||
/* USART2: connected to 2.5mm stereo jack */
|
||||
|
||||
/* Setup GPIO pin GPIO_USART2_TX. */
|
||||
gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_50_MHZ,
|
||||
GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, GPIO_USART2_TX);
|
||||
|
||||
/* Setup UART parameters. */
|
||||
usart_set_baudrate(USART2, 115200);
|
||||
usart_set_databits(USART2, 8);
|
||||
|
@ -92,7 +122,6 @@ static void usart_setup(void)
|
|||
usart_set_mode(USART2, USART_MODE_TX);
|
||||
usart_set_parity(USART2, USART_PARITY_NONE);
|
||||
usart_set_flow_control(USART2, USART_FLOWCONTROL_NONE);
|
||||
|
||||
/* Finally enable the USART. */
|
||||
usart_enable(USART2);
|
||||
}
|
||||
|
@ -106,24 +135,18 @@ static void gpio_setup(void)
|
|||
|
||||
int main(void)
|
||||
{
|
||||
int i, j = 0, c = 0;
|
||||
|
||||
clock_setup();
|
||||
gpio_setup();
|
||||
usart_setup();
|
||||
iob_init(USART2);
|
||||
i2c_setup();
|
||||
attenuator_init(&board_att_cfg, board_att_st);
|
||||
|
||||
/* Blink the LED (PB15) on the board with every transmitted byte. */
|
||||
while (1) {
|
||||
int i;
|
||||
gpio_toggle(GPIOB, GPIO15); /* LED on/off */
|
||||
usart_send_blocking(USART1, c + '0'); /* USART1: Send byte. */
|
||||
usart_send_blocking(USART2, c + '0'); /* USART2: Send byte. */
|
||||
c = (c == 9) ? 0 : c + 1; /* Increment c. */
|
||||
if ((j++ % 80) == 0) { /* Newline after line full. */
|
||||
usart_send_blocking(USART1, '\r');
|
||||
usart_send_blocking(USART1, '\n');
|
||||
usart_send_blocking(USART2, '\r');
|
||||
usart_send_blocking(USART2, '\n');
|
||||
}
|
||||
printf("Hello world\r\n");
|
||||
for (i = 0; i < 800000; i++) /* Wait a bit. */
|
||||
__asm__("nop");
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue