251 lines
6.9 KiB
C
251 lines
6.9 KiB
C
#include <errno.h>
|
|
#include <malloc.h>
|
|
#include <sys/stat.h>
|
|
#include <unistd.h>
|
|
|
|
/* Board */
|
|
#include "pin_mux.h"
|
|
|
|
/* SDK drivers */
|
|
#include "fsl_usart.h"
|
|
|
|
/* FreeRTOS */
|
|
#include "FreeRTOS.h"
|
|
#include "event_groups.h"
|
|
#include "semphr.h"
|
|
#include "task.h"
|
|
|
|
#define APP_STDIO_UART_ID 0
|
|
#define APP_STDIO_UART_INSTANCE USART0
|
|
#define APP_STDIO_UART_CLOCK_ATTACH kFRO12M_to_FLEXCOMM0
|
|
#define APP_STDIO_UART_TX_FIFO_SIZE 16
|
|
#define APP_STDIO_UART_RX_FIFO_SIZE 16
|
|
#define APP_STDIO_UART_TX_BEAT_SIZE (APP_STDIO_UART_TX_FIFO_SIZE - 1)
|
|
#define APP_STDIO_UART_RX_BEAT_SIZE (APP_STDIO_UART_RX_FIFO_SIZE - 4) /* Save room for delayed reception */
|
|
|
|
#define APP_STDIO_UART_IRQ_NR FLEXCOMM0_IRQn
|
|
#define APP_STDIO_UART_IRQ_PRIO (configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY + 1)
|
|
#define APP_STDIO_UART_IRQ_HANDLER FLEXCOMM0_IRQHandler
|
|
|
|
#define APP_STDIO_UART_EVENT_TX_DONE (1 << 0U)
|
|
#define APP_STDIO_UART_EVENT_RX_DONE (1 << 1U)
|
|
#define APP_STDIO_UART_EVENT_ERROR (1 << 2U)
|
|
|
|
static SemaphoreHandle_t s_malloc_lock = NULL;
|
|
|
|
static SemaphoreHandle_t s_stdio_tx_lock = NULL;
|
|
static SemaphoreHandle_t s_stdio_rx_lock = NULL;
|
|
static EventGroupHandle_t s_stdio_event = NULL;
|
|
|
|
/* ========== Internal Use Functions ========== */
|
|
static int app_stdio_init(void) {
|
|
int ret = 0;
|
|
|
|
s_stdio_tx_lock = xSemaphoreCreateMutex();
|
|
if (s_stdio_tx_lock == NULL) {
|
|
return -1;
|
|
}
|
|
|
|
s_stdio_rx_lock = xSemaphoreCreateMutex();
|
|
if (s_stdio_rx_lock == NULL) {
|
|
ret = -1;
|
|
goto free_tx_sem_exit;
|
|
}
|
|
|
|
s_stdio_event = xEventGroupCreate();
|
|
if (s_stdio_event == NULL) {
|
|
ret = -1;
|
|
goto free_rx_sem_exit;
|
|
}
|
|
|
|
CLOCK_AttachClk(APP_STDIO_UART_CLOCK_ATTACH);
|
|
|
|
usart_config_t usart_config;
|
|
USART_GetDefaultConfig(&usart_config);
|
|
|
|
usart_config.baudRate_Bps = 115200U;
|
|
usart_config.txWatermark = 0U;
|
|
usart_config.rxWatermark = APP_STDIO_UART_RX_BEAT_SIZE;
|
|
usart_config.enableTx = true;
|
|
usart_config.enableRx = true;
|
|
usart_config.bitCountPerChar = kUSART_8BitsPerChar;
|
|
usart_config.stopBitCount = kUSART_OneStopBit;
|
|
usart_config.parityMode = kUSART_ParityDisabled;
|
|
|
|
uint32_t stdio_fc_clk_freq = CLOCK_GetFlexCommClkFreq(APP_STDIO_UART_ID);
|
|
if (USART_Init(APP_STDIO_UART_INSTANCE, &usart_config, stdio_fc_clk_freq) != kStatus_Success) {
|
|
ret = -1;
|
|
goto free_event_exit;
|
|
}
|
|
|
|
USART_SetTxFifoWatermark(APP_STDIO_UART_INSTANCE, 0); /* Has to be set to 0 to detect TX done condition */
|
|
USART_SetRxFifoWatermark(APP_STDIO_UART_INSTANCE, APP_STDIO_UART_RX_BEAT_SIZE); /* Might be adjusted on-the-fly */
|
|
|
|
NVIC_SetPriority(APP_STDIO_UART_IRQ_NR, APP_STDIO_UART_IRQ_PRIO);
|
|
EnableIRQ(APP_STDIO_UART_IRQ_NR);
|
|
|
|
return ret;
|
|
|
|
free_event_exit:
|
|
vEventGroupDelete(s_stdio_event);
|
|
|
|
free_rx_sem_exit:
|
|
vSemaphoreDelete(s_stdio_rx_lock);
|
|
|
|
free_tx_sem_exit:
|
|
vSemaphoreDelete(s_stdio_tx_lock);
|
|
|
|
return ret;
|
|
}
|
|
|
|
void APP_STDIO_UART_IRQ_HANDLER(void) {
|
|
uint32_t event_flag = 0UL;
|
|
|
|
uint32_t interrupts_enabled = USART_GetEnabledInterrupts(APP_STDIO_UART_INSTANCE);
|
|
uint32_t fifo_int_status = APP_STDIO_UART_INSTANCE->FIFOINTSTAT;
|
|
|
|
USART_ClearStatusFlags(APP_STDIO_UART_INSTANCE, kUSART_AllClearFlags);
|
|
|
|
if ((interrupts_enabled & kUSART_TxLevelInterruptEnable) && (fifo_int_status & USART_FIFOINTSTAT_TXLVL_MASK)) {
|
|
USART_DisableInterrupts(APP_STDIO_UART_INSTANCE, kUSART_TxLevelInterruptEnable);
|
|
event_flag |= APP_STDIO_UART_EVENT_TX_DONE;
|
|
}
|
|
|
|
if ((interrupts_enabled & kUSART_RxLevelInterruptEnable) && (fifo_int_status & USART_FIFOINTSTAT_RXLVL_MASK)) {
|
|
USART_DisableInterrupts(APP_STDIO_UART_INSTANCE, kUSART_RxLevelInterruptEnable);
|
|
event_flag |= APP_STDIO_UART_EVENT_RX_DONE;
|
|
}
|
|
|
|
BaseType_t higher_prio_task_woken = pdFALSE;
|
|
|
|
xEventGroupSetBitsFromISR(s_stdio_event, event_flag, &higher_prio_task_woken);
|
|
portYIELD_FROM_ISR(higher_prio_task_woken);
|
|
}
|
|
|
|
int app_syscalls_init(void) {
|
|
s_malloc_lock = xSemaphoreCreateRecursiveMutex();
|
|
if (s_malloc_lock == NULL) {
|
|
return -1;
|
|
}
|
|
|
|
if (app_stdio_init() != 0) {
|
|
return -2;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void __malloc_lock(struct _reent *reent) {
|
|
xSemaphoreTakeRecursive(s_malloc_lock, portMAX_DELAY);
|
|
}
|
|
|
|
void __malloc_unlock(struct _reent *reent) {
|
|
xSemaphoreGiveRecursive(s_malloc_lock);
|
|
}
|
|
|
|
int _read(int file, char *ptr, int len) {
|
|
if (file != STDIN_FILENO) {
|
|
return 0;
|
|
}
|
|
|
|
xSemaphoreTake(s_stdio_rx_lock, portMAX_DELAY);
|
|
|
|
USART_SetRxFifoWatermark(APP_STDIO_UART_INSTANCE, 0);
|
|
USART_EnableInterrupts(APP_STDIO_UART_INSTANCE, kUSART_RxLevelInterruptEnable);
|
|
|
|
xEventGroupWaitBits(s_stdio_event, APP_STDIO_UART_EVENT_RX_DONE, pdTRUE, pdFALSE, portMAX_DELAY);
|
|
|
|
uint8_t rx_level = USART_GetRxFifoCount(APP_STDIO_UART_INSTANCE);
|
|
|
|
if (rx_level > len) {
|
|
rx_level = len;
|
|
}
|
|
|
|
for (uint8_t i = 0; i < rx_level; i++) {
|
|
ptr[i] = USART_ReadByte(APP_STDIO_UART_INSTANCE);
|
|
}
|
|
|
|
xSemaphoreGive(s_stdio_rx_lock);
|
|
return rx_level;
|
|
}
|
|
|
|
int _write(int file, char *buf, int len) {
|
|
if (file != STDOUT_FILENO && file != STDERR_FILENO) {
|
|
return 0;
|
|
}
|
|
|
|
xSemaphoreTake(s_stdio_tx_lock, portMAX_DELAY);
|
|
|
|
int xfer_count = len / APP_STDIO_UART_TX_BEAT_SIZE;
|
|
int bytes_remaining = len % APP_STDIO_UART_TX_BEAT_SIZE;
|
|
if (bytes_remaining) {
|
|
xfer_count++;
|
|
}
|
|
|
|
for (int i = 0; i < xfer_count; i++) {
|
|
uint32_t tx_bytes = APP_STDIO_UART_TX_BEAT_SIZE;
|
|
|
|
if (i == xfer_count - 1) {
|
|
if (bytes_remaining) {
|
|
tx_bytes = bytes_remaining;
|
|
}
|
|
}
|
|
|
|
/* Hold TX operation before enabling level interrupt, otherwise a level interrupt will fire instantly */
|
|
APP_STDIO_UART_INSTANCE->CTL |= USART_CTL_TXDIS_MASK;
|
|
|
|
/* Fill FIFO */
|
|
for (uint32_t j = 0; j < tx_bytes; j++) {
|
|
USART_WriteByte(APP_STDIO_UART_INSTANCE, buf[i * APP_STDIO_UART_TX_BEAT_SIZE + j]);
|
|
}
|
|
|
|
USART_EnableInterrupts(APP_STDIO_UART_INSTANCE, kUSART_TxLevelInterruptEnable);
|
|
|
|
/* Begin TX transfer */
|
|
APP_STDIO_UART_INSTANCE->CTL &= ~(USART_CTL_TXDIS_MASK);
|
|
|
|
/* Wait for TX complete */
|
|
xEventGroupWaitBits(s_stdio_event, APP_STDIO_UART_EVENT_TX_DONE, pdTRUE, pdFALSE, portMAX_DELAY);
|
|
}
|
|
|
|
xSemaphoreGive(s_stdio_tx_lock);
|
|
|
|
return len;
|
|
}
|
|
|
|
int _open(const char *path, int flags, ...) {
|
|
return -1;
|
|
}
|
|
|
|
int _close(int file) {
|
|
errno = -EBADF;
|
|
return -1;
|
|
}
|
|
|
|
int _fstat(int file, struct stat *st) {
|
|
if ((STDOUT_FILENO == file) || (STDERR_FILENO == file)) {
|
|
st->st_mode = S_IFCHR;
|
|
return 0;
|
|
} else {
|
|
errno = EBADF;
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
int _getpid() {
|
|
return 1;
|
|
}
|
|
|
|
int _isatty(int file) {
|
|
return 1;
|
|
}
|
|
|
|
int _kill(int pid, int sig) {
|
|
errno = -EINVAL;
|
|
|
|
return -1;
|
|
}
|
|
|
|
int _lseek(int file, int offset, int whence) {
|
|
return 0;
|
|
} |