Compare commits
2 Commits
9f05489b3a
...
62baffe992
| Author | SHA1 | Date | |
|---|---|---|---|
| 62baffe992 | |||
| 5af462ac4f |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1 +1,2 @@
|
|||||||
|
.vscode
|
||||||
build/
|
build/
|
||||||
18
.vscode/c_cpp_properties.json
vendored
Normal file
18
.vscode/c_cpp_properties.json
vendored
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
{
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"includePath": [
|
||||||
|
"${workspaceFolder}/**",
|
||||||
|
"${ZEPHYR_BASE}/include/**",
|
||||||
|
"${ZEPHYR_BASE}/kernel/include/**",
|
||||||
|
"${workspaceFolder}/build/zephyr/include/generated/**"
|
||||||
|
],
|
||||||
|
//"compilerPath": "~/zephyr-sdk-0.17.4/arm-zephyr-eabi/bin/arm-zephyr-eabi-gcc",
|
||||||
|
"cStandard": "c11",
|
||||||
|
"cppStandard": "c++17",
|
||||||
|
"compileCommands": "${workspaceFolder}/build/compile_commands.json",
|
||||||
|
"intelliSenseMode": "gcc-arm"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"version": 4
|
||||||
|
}
|
||||||
27
.vscode/launch.json
vendored
Normal file
27
.vscode/launch.json
vendored
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
{
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": "Zephyr west debugserver",
|
||||||
|
"type": "cortex-debug",
|
||||||
|
"request": "attach",
|
||||||
|
"servertype": "external",
|
||||||
|
"cwd": "${workspaceFolder}",
|
||||||
|
|
||||||
|
"executable": "${workspaceFolder}/build/zephyr/zephyr.elf",
|
||||||
|
"gdbTarget": "localhost:3333",
|
||||||
|
|
||||||
|
"svdFile": "${env:ZEPHYR_BASE}/../modules/hal/nordic/nrfx/bsp/stable/mdk/nrf54l15_application.svd",
|
||||||
|
"rtos": "Zephyr",
|
||||||
|
|
||||||
|
"overrideAttachCommands": [
|
||||||
|
"monitor reset halt",
|
||||||
|
],
|
||||||
|
|
||||||
|
"postAttachCommands": [
|
||||||
|
//"tbreak main",
|
||||||
|
"continue"
|
||||||
|
],
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -6,7 +6,7 @@
|
|||||||
test_uart: test_uart {
|
test_uart: test_uart {
|
||||||
compatible = "uart-interrupt-poll-bridge";
|
compatible = "uart-interrupt-poll-bridge";
|
||||||
uart = <&uart20>;
|
uart = <&uart20>;
|
||||||
timer = <&timer00>;
|
counter = <&timer00>;
|
||||||
interrupts = <1 2>;
|
interrupts = <1 2>;
|
||||||
interrupt-parent = <&nvic>;
|
interrupt-parent = <&nvic>;
|
||||||
status = "okay";
|
status = "okay";
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
config UART_INTERRUPT_POLL_BRIDGE
|
config UART_INTERRUPT_POLL_BRIDGE
|
||||||
bool "UART interrupt/poll bridge driver"
|
bool "UART interrupt/poll bridge driver"
|
||||||
default y
|
default y
|
||||||
|
select UART_USE_RUNTIME_CONFIGURE
|
||||||
|
|
||||||
config UART_INTERRUPT_POLL_BRIDGE_QUEUE_SIZE
|
config UART_INTERRUPT_POLL_BRIDGE_QUEUE_SIZE
|
||||||
int "UART interrupt/poll bridge driver rx / tx buffer size"
|
int "UART interrupt/poll bridge driver rx / tx buffer size"
|
||||||
|
|||||||
@@ -1,31 +1,49 @@
|
|||||||
#define DT_DRV_COMPAT uart_interrupt_poll_bridge
|
#define DT_DRV_COMPAT uart_interrupt_poll_bridge
|
||||||
|
|
||||||
#include <zephyr/drivers/uart.h>
|
#include <zephyr/drivers/uart.h>
|
||||||
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
|
#include <zephyr/spinlock.h>
|
||||||
|
#if IS_ENABLED(CONFIG_UART_INTERRUPT_DRIVEN)
|
||||||
|
#include <zephyr/drivers/counter.h>
|
||||||
#include <zephyr/sys/ring_buffer.h>
|
#include <zephyr/sys/ring_buffer.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define REDUCE_TO_BIT(obj) (!!obj)
|
||||||
|
|
||||||
struct uart_pti_bridge_config {
|
struct uart_pti_bridge_config {
|
||||||
const struct device *uart;
|
const struct device *uart;
|
||||||
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
|
#if IS_ENABLED(CONFIG_UART_INTERRUPT_DRIVEN)
|
||||||
const struct device *timer;
|
const struct device *counter;
|
||||||
const uint8_t interrupt_line;
|
const uint8_t interrupt_line;
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
struct uart_pti_bridge_data {
|
struct uart_pti_bridge_data {
|
||||||
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
|
struct k_spinlock lock;
|
||||||
|
#if IS_ENABLED(CONFIG_UART_INTERRUPT_DRIVEN)
|
||||||
struct ring_buf *rx_buf;
|
struct ring_buf *rx_buf;
|
||||||
struct ring_buf *tx_buf;
|
struct ring_buf *tx_buf;
|
||||||
|
uart_irq_callback_user_data_t cb;
|
||||||
|
void *user_data;
|
||||||
|
union {
|
||||||
|
struct {
|
||||||
|
const uint8_t irq_triggered : 4;
|
||||||
|
const uint8_t irq_enabled : 4;
|
||||||
|
};
|
||||||
|
struct {
|
||||||
|
bool irq_tx_ready_triggered : 1;
|
||||||
|
bool irq_tx_complete_triggered: 1;
|
||||||
|
bool irq_rx_ready_triggered : 1;
|
||||||
|
bool irq_err_triggered : 1;
|
||||||
|
bool irq_tx_enabled : 1;
|
||||||
|
bool : 1;
|
||||||
|
bool irq_rx_enabled : 1;
|
||||||
|
bool irq_err_enabled : 1;
|
||||||
|
|
||||||
|
};
|
||||||
|
};
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
int uart_pti_bridge_init(const struct device *dev) {
|
|
||||||
ARG_UNUSED(dev);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int uart_pti_bridge_poll_in(const struct device *dev, unsigned char *c) {
|
static int uart_pti_bridge_poll_in(const struct device *dev, unsigned char *c) {
|
||||||
const struct uart_pti_bridge_config *config = dev->config;
|
const struct uart_pti_bridge_config *config = dev->config;
|
||||||
|
|
||||||
@@ -48,7 +66,7 @@ static int uart_pti_bridge_err_check(const struct device *dev) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifdef CONFIG_UART_USE_RUNTIME_CONFIGURE
|
#if IS_ENABLED(CONFIG_UART_USE_RUNTIME_CONFIGURE)
|
||||||
static int uart_pti_bridge_configure(const struct device *dev,
|
static int uart_pti_bridge_configure(const struct device *dev,
|
||||||
const struct uart_config *cfg) {
|
const struct uart_config *cfg) {
|
||||||
ARG_UNUSED(dev);
|
ARG_UNUSED(dev);
|
||||||
@@ -64,6 +82,213 @@ static int uart_pti_bridge_config_get(const struct device *dev,
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#if IS_ENABLED(CONFIG_UART_INTERRUPT_DRIVEN)
|
||||||
|
int uart_pti_bridge_fifo_fill(const struct device *dev, const uint8_t *msg, int len) {
|
||||||
|
struct uart_pti_bridge_data *data = dev->data;
|
||||||
|
|
||||||
|
k_spinlock_key_t key = k_spin_lock(&data->lock);
|
||||||
|
uint32_t bytes_written = ring_buf_put(data->tx_buf, msg, len);
|
||||||
|
k_spin_unlock(&data->lock, key);
|
||||||
|
|
||||||
|
return bytes_written;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int uart_pti_bridge_fifo_read(const struct device *dev, uint8_t *msg, const int size) {
|
||||||
|
struct uart_pti_bridge_data *data = dev->data;
|
||||||
|
|
||||||
|
k_spinlock_key_t key = k_spin_lock(&data->lock);
|
||||||
|
uint32_t bytes_read = ring_buf_get(data->rx_buf, msg, size);
|
||||||
|
k_spin_unlock(&data->lock, key);
|
||||||
|
|
||||||
|
return bytes_read;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void uart_pti_bridge_irq_tx_enable(const struct device *dev) {
|
||||||
|
struct uart_pti_bridge_data *data = dev->data;
|
||||||
|
|
||||||
|
data->irq_tx_enabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void uart_pti_bridge_irq_tx_disable(const struct device *dev) {
|
||||||
|
struct uart_pti_bridge_data *data = dev->data;
|
||||||
|
|
||||||
|
data->irq_tx_enabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int uart_pti_bridge_irq_tx_ready(const struct device *dev) {
|
||||||
|
struct uart_pti_bridge_data *data = dev->data;
|
||||||
|
|
||||||
|
return data->irq_tx_ready_triggered;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int uart_pti_bridge_irq_tx_complete(const struct device *dev) {
|
||||||
|
struct uart_pti_bridge_data *data = dev->data;
|
||||||
|
|
||||||
|
return data->irq_tx_complete_triggered;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void uart_pti_bridge_irq_rx_enable(const struct device *dev) {
|
||||||
|
struct uart_pti_bridge_data *data = dev->data;
|
||||||
|
|
||||||
|
data->irq_rx_enabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void uart_pti_bridge_irq_rx_disable(const struct device *dev) {
|
||||||
|
struct uart_pti_bridge_data *data = dev->data;
|
||||||
|
|
||||||
|
data->irq_rx_enabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int uart_pti_bridge_irq_rx_ready(const struct device *dev) {
|
||||||
|
struct uart_pti_bridge_data *data = dev->data;
|
||||||
|
|
||||||
|
return data->irq_rx_ready_triggered;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void uart_pti_bridge_irq_err_enable(const struct device *dev) {
|
||||||
|
struct uart_pti_bridge_data *data = dev->data;
|
||||||
|
|
||||||
|
data->irq_err_enabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void uart_pti_bridge_irq_err_disable(const struct device *dev) {
|
||||||
|
struct uart_pti_bridge_data *data = dev->data;
|
||||||
|
|
||||||
|
data->irq_err_enabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int uart_pti_bridge_irq_is_pending(const struct device *dev) {
|
||||||
|
struct uart_pti_bridge_data *data = dev->data;
|
||||||
|
|
||||||
|
return REDUCE_TO_BIT(data->irq_triggered);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int uart_pti_bridge_irq_update(const struct device *dev) {
|
||||||
|
ARG_UNUSED(dev);
|
||||||
|
return 1; // success
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void uart_pti_bridge_callback_set(const struct device *dev, uart_irq_callback_user_data_t cb, void *user_data) {
|
||||||
|
struct uart_pti_bridge_data *data = dev->data;
|
||||||
|
|
||||||
|
k_spinlock_key_t key = k_spin_lock(&data->lock);
|
||||||
|
data->cb = cb;
|
||||||
|
data->user_data = user_data;
|
||||||
|
k_spin_unlock(&data->lock, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void uart_pti_bridge_timer_irq(const struct device *timer_dev, void *user_data) {
|
||||||
|
ARG_UNUSED(timer_dev);
|
||||||
|
|
||||||
|
const struct device *dev = user_data;
|
||||||
|
struct uart_pti_bridge_data *data = dev->data;
|
||||||
|
|
||||||
|
k_spinlock_key_t key = k_spin_lock(&data->lock);
|
||||||
|
|
||||||
|
data->irq_tx_ready_triggered = REDUCE_TO_BIT(ring_buf_space_get(data->tx_buf));
|
||||||
|
data->irq_tx_complete_triggered = REDUCE_TO_BIT(ring_buf_is_empty(data->tx_buf));
|
||||||
|
data->irq_rx_ready_triggered = REDUCE_TO_BIT(!ring_buf_is_empty(data->rx_buf));
|
||||||
|
data->irq_err_triggered = REDUCE_TO_BIT(uart_pti_bridge_err_check(dev));
|
||||||
|
|
||||||
|
if (data->irq_tx_ready_triggered && !data->irq_tx_complete_triggered) {
|
||||||
|
uint8_t chunk;
|
||||||
|
if (ring_buf_get(data->tx_buf, &chunk, 1)) {
|
||||||
|
uart_poll_out(dev, chunk);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data->irq_rx_enabled) {
|
||||||
|
uint32_t rx_buf_free_space = ring_buf_space_get(data->rx_buf);
|
||||||
|
uint8_t chunk;
|
||||||
|
|
||||||
|
for (uint32_t bytes_read = 0; bytes_read <= rx_buf_free_space; bytes_read++) {
|
||||||
|
if (uart_poll_in(dev, &chunk) < 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ring_buf_put(data->rx_buf, &chunk, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
k_spin_unlock(&data->lock, key);
|
||||||
|
|
||||||
|
if (data->cb && data->irq_triggered) {
|
||||||
|
data->cb(dev, data->user_data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t uart_pti_bridge_us_per_byte(const struct uart_config *cfg)
|
||||||
|
{
|
||||||
|
uint8_t bits = 1; // start bit
|
||||||
|
|
||||||
|
// data bits
|
||||||
|
switch (cfg->data_bits) {
|
||||||
|
case UART_CFG_DATA_BITS_5: bits += 5; break;
|
||||||
|
case UART_CFG_DATA_BITS_6: bits += 6; break;
|
||||||
|
case UART_CFG_DATA_BITS_7: bits += 7; break;
|
||||||
|
case UART_CFG_DATA_BITS_8: bits += 8; break;
|
||||||
|
case UART_CFG_DATA_BITS_9: bits += 9; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// parity bit
|
||||||
|
if (cfg->parity != UART_CFG_PARITY_NONE) {
|
||||||
|
bits += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// stop bits
|
||||||
|
switch (cfg->stop_bits) {
|
||||||
|
case UART_CFG_STOP_BITS_0_5: break; // rare, ignore
|
||||||
|
case UART_CFG_STOP_BITS_1: bits += 1; break;
|
||||||
|
case UART_CFG_STOP_BITS_1_5: bits += 1; break; // round down
|
||||||
|
case UART_CFG_STOP_BITS_2: bits += 2; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// round up to ensure buffer is always large enough
|
||||||
|
return (bits * 1000000 + cfg->baudrate - 1) / cfg->baudrate;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
int uart_pti_bridge_init(const struct device *dev) {
|
||||||
|
#if IS_ENABLED(CONFIG_UART_INTERRUPT_DRIVEN)
|
||||||
|
const struct uart_pti_bridge_config *config = dev->config;
|
||||||
|
|
||||||
|
struct uart_config cfg;
|
||||||
|
uart_config_get(config->uart, &cfg);
|
||||||
|
|
||||||
|
const uint32_t us_per_byte = uart_pti_bridge_us_per_byte(&cfg);
|
||||||
|
|
||||||
|
struct counter_top_cfg top_cfg = {
|
||||||
|
.callback = uart_pti_bridge_timer_irq,
|
||||||
|
.ticks = counter_us_to_ticks(config->counter, us_per_byte),
|
||||||
|
.user_data = (struct device *)dev,
|
||||||
|
.flags = 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
counter_set_top_value(config->counter, &top_cfg);
|
||||||
|
counter_start(config->counter);
|
||||||
|
#else
|
||||||
|
ARG_UNUSED(dev);
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static DEVICE_API(uart, uart_interrupt_poll_bridge_api) = {
|
static DEVICE_API(uart, uart_interrupt_poll_bridge_api) = {
|
||||||
.poll_in = uart_pti_bridge_poll_in,
|
.poll_in = uart_pti_bridge_poll_in,
|
||||||
.poll_out = uart_pti_bridge_poll_out,
|
.poll_out = uart_pti_bridge_poll_out,
|
||||||
@@ -73,20 +298,20 @@ static DEVICE_API(uart, uart_interrupt_poll_bridge_api) = {
|
|||||||
.config_get = uart_pti_bridge_config_get,
|
.config_get = uart_pti_bridge_config_get,
|
||||||
#endif
|
#endif
|
||||||
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
|
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
|
||||||
.fifo_fill = NULL,
|
.fifo_fill = uart_pti_bridge_fifo_fill,
|
||||||
.fifo_read = NULL,
|
.fifo_read = uart_pti_bridge_fifo_read,
|
||||||
.irq_tx_enable = NULL,
|
.irq_tx_enable = uart_pti_bridge_irq_tx_enable,
|
||||||
.irq_tx_disable = NULL,
|
.irq_tx_disable = uart_pti_bridge_irq_tx_disable,
|
||||||
.irq_tx_ready = NULL,
|
.irq_tx_ready = uart_pti_bridge_irq_tx_ready,
|
||||||
.irq_tx_complete = NULL,
|
.irq_tx_complete = uart_pti_bridge_irq_tx_complete,
|
||||||
.irq_rx_enable = NULL,
|
.irq_rx_enable = uart_pti_bridge_irq_rx_enable,
|
||||||
.irq_rx_disable = NULL,
|
.irq_rx_disable = uart_pti_bridge_irq_rx_disable,
|
||||||
.irq_rx_ready = NULL,
|
.irq_rx_ready = uart_pti_bridge_irq_rx_ready,
|
||||||
.irq_err_enable = NULL,
|
.irq_err_enable = uart_pti_bridge_irq_err_enable,
|
||||||
.irq_err_disable = NULL,
|
.irq_err_disable = uart_pti_bridge_irq_err_disable,
|
||||||
.irq_is_pending = NULL,
|
.irq_is_pending = uart_pti_bridge_irq_is_pending,
|
||||||
.irq_update = NULL,
|
.irq_update = uart_pti_bridge_irq_update,
|
||||||
.irq_callback_set = NULL,
|
.irq_callback_set = uart_pti_bridge_callback_set,
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -107,7 +332,7 @@ static DEVICE_API(uart, uart_interrupt_poll_bridge_api) = {
|
|||||||
static const struct uart_pti_bridge_config uart_pti_bridge_config_##inst = { \
|
static const struct uart_pti_bridge_config uart_pti_bridge_config_##inst = { \
|
||||||
.uart = DEVICE_DT_GET(DT_INST_PHANDLE(inst, uart)), \
|
.uart = DEVICE_DT_GET(DT_INST_PHANDLE(inst, uart)), \
|
||||||
COND_CODE_1(CONFIG_UART_INTERRUPT_DRIVEN, ( \
|
COND_CODE_1(CONFIG_UART_INTERRUPT_DRIVEN, ( \
|
||||||
.timer = DEVICE_DT_GET(DT_INST_PHANDLE(inst, timer)), \
|
.counter = DEVICE_DT_GET(DT_INST_PHANDLE(inst, counter)), \
|
||||||
.interrupt_line = DT_INST_IRQN(inst), \
|
.interrupt_line = DT_INST_IRQN(inst), \
|
||||||
), ()) \
|
), ()) \
|
||||||
}; \
|
}; \
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ properties:
|
|||||||
interrupts:
|
interrupts:
|
||||||
type: array
|
type: array
|
||||||
required: true
|
required: true
|
||||||
timer:
|
counter:
|
||||||
type: phandle
|
type: phandle
|
||||||
required: true
|
required: true
|
||||||
uart:
|
uart:
|
||||||
|
|||||||
8
prj.conf
8
prj.conf
@@ -1,2 +1,8 @@
|
|||||||
CONFIG_UART_INTERRUPT_DRIVEN=y
|
CONFIG_UART_INTERRUPT_DRIVEN=y
|
||||||
CONFIG_COUNTER=y
|
CONFIG_COUNTER=y
|
||||||
|
|
||||||
|
# Disable compiler optimization
|
||||||
|
CONFIG_DEBUG=y
|
||||||
|
CONFIG_NO_OPTIMIZATIONS=y
|
||||||
|
CONFIG_THREAD_RUNTIME_STATS=y
|
||||||
|
CONFIG_THREAD_RUNTIME_STATS_USE_TIMING_FUNCTIONS=y
|
||||||
84
src/main.cpp
84
src/main.cpp
@@ -5,17 +5,91 @@
|
|||||||
const struct device *test_uart = DEVICE_DT_GET(DT_ALIAS(testuart));
|
const struct device *test_uart = DEVICE_DT_GET(DT_ALIAS(testuart));
|
||||||
|
|
||||||
|
|
||||||
|
// TEST GENERATED CODE START
|
||||||
|
#include <zephyr/sys/ring_buffer.h>
|
||||||
|
#include <zephyr/spinlock.h>
|
||||||
|
|
||||||
|
#define RX_BUF_SIZE 256
|
||||||
|
#define TX_BUF_SIZE 256
|
||||||
|
|
||||||
|
RING_BUF_DECLARE(rx_buf, RX_BUF_SIZE);
|
||||||
|
RING_BUF_DECLARE(tx_buf, TX_BUF_SIZE);
|
||||||
|
|
||||||
|
static struct k_spinlock uart_lock;
|
||||||
|
|
||||||
|
static void uart_isr(const struct device *dev, void *user_data)
|
||||||
|
{
|
||||||
|
uart_irq_update(dev);
|
||||||
|
|
||||||
|
if (uart_irq_rx_ready(dev)) {
|
||||||
|
uint8_t byte;
|
||||||
|
while (uart_fifo_read(dev, &byte, 1) == 1) {
|
||||||
|
k_spinlock_key_t key = k_spin_lock(&uart_lock);
|
||||||
|
ring_buf_put(&rx_buf, &byte, 1);
|
||||||
|
k_spin_unlock(&uart_lock, key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (uart_irq_tx_ready(dev)) {
|
||||||
|
uint8_t byte;
|
||||||
|
k_spinlock_key_t key = k_spin_lock(&uart_lock);
|
||||||
|
if (ring_buf_get(&tx_buf, &byte, 1) == 1) {
|
||||||
|
k_spin_unlock(&uart_lock, key);
|
||||||
|
uart_fifo_fill(dev, &byte, 1);
|
||||||
|
} else {
|
||||||
|
k_spin_unlock(&uart_lock, key);
|
||||||
|
uart_irq_tx_disable(dev); // nothing left, stop firing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Call once at init */
|
||||||
|
void uart_init(const struct device *dev)
|
||||||
|
{
|
||||||
|
uart_irq_callback_set(dev, uart_isr);
|
||||||
|
uart_irq_rx_enable(dev);
|
||||||
|
/* TX IRQ is enabled on demand when we have data to send */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Write bytes to TX — call from thread context */
|
||||||
|
int uart_write(const struct device *dev, const uint8_t *data, size_t len)
|
||||||
|
{
|
||||||
|
k_spinlock_key_t key = k_spin_lock(&uart_lock);
|
||||||
|
uint32_t written = ring_buf_put(&tx_buf, data, len);
|
||||||
|
k_spin_unlock(&uart_lock, key);
|
||||||
|
|
||||||
|
uart_irq_tx_enable(dev); // kick off TX if not already running
|
||||||
|
return written;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read bytes from RX — call from thread context */
|
||||||
|
int uart_read(const struct device *dev, uint8_t *data, size_t len)
|
||||||
|
{
|
||||||
|
k_spinlock_key_t key = k_spin_lock(&uart_lock);
|
||||||
|
uint32_t read = ring_buf_get(&rx_buf, data, len);
|
||||||
|
k_spin_unlock(&uart_lock, key);
|
||||||
|
return read;
|
||||||
|
}
|
||||||
|
// TEST GENERATED CODE END
|
||||||
|
|
||||||
|
|
||||||
int main(void) {
|
int main(void) {
|
||||||
|
|
||||||
const char msg [] = "Hello World";
|
const uint8_t msg [] = "Hello World\r\n";
|
||||||
|
|
||||||
|
uart_irq_callback_set(test_uart, uart_isr);
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
for (char c : msg) {
|
uart_write(test_uart, msg, sizeof(msg));
|
||||||
uart_poll_out(test_uart, c);
|
|
||||||
}
|
|
||||||
|
|
||||||
k_sleep(K_MSEC(100));
|
|
||||||
|
k_thread_runtime_stats_t stats;
|
||||||
|
|
||||||
|
k_thread_runtime_stats_all_get(&stats);
|
||||||
|
uint8_t buff[32];
|
||||||
|
sprintf((char*)&buff, "total cycles: %15llu\r\n", stats.execution_cycles);
|
||||||
|
uart_write(test_uart, buff, sizeof(buff));
|
||||||
|
k_sleep(K_MSEC(1000));
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user