USART: Main implemented.
This commit is contained in:
@@ -46,17 +46,18 @@ struct USART {
|
|||||||
static struct USART *const USART2 = (struct SYSCFG *)USART2_BASE;
|
static struct USART *const USART2 = (struct SYSCFG *)USART2_BASE;
|
||||||
static struct USART *const USART3 = (struct SYSCFG *)USART3_BASE;
|
static struct USART *const USART3 = (struct SYSCFG *)USART3_BASE;
|
||||||
|
|
||||||
#define USART_SR_CTS 0x0200
|
#define USART_SR_CTS (1 << 9)
|
||||||
#define USART_SR_LBD 0x0100
|
#define USART_SR_LBD (1 << 8)
|
||||||
#define USART_SR_TXE 0x0080
|
#define USART_SR_TXE (1 << 7)
|
||||||
#define USART_SR_TC 0x0040
|
#define USART_SR_TC (1 << 6)
|
||||||
#define USART_SR_RXNE 0x0020
|
#define USART_SR_RXNE (1 << 5)
|
||||||
#define USART_SR_IDLE 0x0010
|
#define USART_SR_IDLE (1 << 4)
|
||||||
#define USART_SR_ORE 0x0008
|
#define USART_SR_ORE (1 << 3)
|
||||||
#define USART_SR_NE 0x0004
|
#define USART_SR_NE (1 << 2)
|
||||||
#define USART_SR_FE 0x0002
|
#define USART_SR_FE (1 << 1)
|
||||||
#define USART_SR_PE 0x0001
|
#define USART_SR_PE (1 << 0)
|
||||||
|
|
||||||
|
#define USART_CR1_TXEIE (1 << 7)
|
||||||
|
|
||||||
|
|
||||||
static struct USART *
|
static struct USART *
|
||||||
@@ -87,12 +88,28 @@ static const struct brr_setting brr_table[] = {
|
|||||||
{ B921600, ( 2 << 4)|7},
|
{ B921600, ( 2 << 4)|7},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void *usart_main (void *arg);
|
||||||
|
|
||||||
|
struct usart_stat {
|
||||||
|
uint32_t tx;
|
||||||
|
uint32_t rx;
|
||||||
|
uint32_t rx_break;
|
||||||
|
uint32_t err_rx_overflow; /* software side */
|
||||||
|
uint32_t err_rx_overrun; /* hardware side */
|
||||||
|
uint32_t err_rx_noise;
|
||||||
|
uint32_t err_rx_parity;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct usart_stat usart2_stat;
|
||||||
|
static struct usart_stat usart3_stat;
|
||||||
|
|
||||||
void
|
void
|
||||||
usart_init (void)
|
usart_init (void)
|
||||||
{
|
{
|
||||||
RCC->APB1ENR |= ((1 << 18) | (1 << 17));
|
RCC->APB1ENR |= ((1 << 18) | (1 << 17));
|
||||||
RCC->APB1RSTR = ((1 << 18) | (1 << 17));
|
RCC->APB1RSTR = ((1 << 18) | (1 << 17));
|
||||||
RCC->APB1RSTR = 0;
|
RCC->APB1RSTR = 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -107,7 +124,7 @@ usart_init (void)
|
|||||||
int
|
int
|
||||||
usart_config (uint8_t dev_no, uint32_t config_bits)
|
usart_config (uint8_t dev_no, uint32_t config_bits)
|
||||||
{
|
{
|
||||||
struct USART *dev = get_usart_dev (dev_no);
|
struct USART *USARTx = get_usart_dev (dev_no);
|
||||||
uint8_t baud_spec = (config & 0x3f);
|
uint8_t baud_spec = (config & 0x3f);
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
@@ -118,7 +135,9 @@ usart_config (uint8_t dev_no, uint32_t config_bits)
|
|||||||
if (i >= NUM_BAUD)
|
if (i >= NUM_BAUD)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
dev->BRR = brr_table[i].brr_value;
|
USARTx->BRR = brr_table[i].brr_value;
|
||||||
|
|
||||||
|
/* No PEIE, CTSIE, TCIE, IDLEIE, LBDIE */
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -142,7 +161,7 @@ struct rb {
|
|||||||
/*
|
/*
|
||||||
* Note: size = 1024 can still work, regardless of the limit of 10-bit.
|
* Note: size = 1024 can still work, regardless of the limit of 10-bit.
|
||||||
*/
|
*/
|
||||||
static init
|
static void
|
||||||
rb_init (struct rng_rb *rb, uint32_t *p, uint16_t size)
|
rb_init (struct rng_rb *rb, uint32_t *p, uint16_t size)
|
||||||
{
|
{
|
||||||
rb->buf = p;
|
rb->buf = p;
|
||||||
@@ -274,3 +293,159 @@ rb_write (struct rng_rb *rb, uint8_t *buf, uint16_t buflen)
|
|||||||
}
|
}
|
||||||
chopstx_mutex_unlock (&rb->m);
|
chopstx_mutex_unlock (&rb->m);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
rb_empty_check (void *arg)
|
||||||
|
{
|
||||||
|
struct rng_rb *rb = arg;
|
||||||
|
return rb->empty != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
rb_get_prepare_poll (struct rb *rb, chopstx_poll_cond_t *poll_desc)
|
||||||
|
{
|
||||||
|
poll_desc->type = CHOPSTX_POLL_COND;
|
||||||
|
poll_desc->ready = 0;
|
||||||
|
poll_desc->cond = &rb->data_available;
|
||||||
|
poll_desc->mutex = &rb->m;
|
||||||
|
poll_desc->check = rb_empty_check;
|
||||||
|
poll_desc->arg = rb;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define INTR_REQ_USART2 38
|
||||||
|
#define INTR_REQ_USART3 39
|
||||||
|
|
||||||
|
static uint8_t buf_usart2_rb_a2h[256];
|
||||||
|
static uint8_t buf_usart2_rb_h2a[512];
|
||||||
|
static uint8_t buf_usart3_rb_a2h[256];
|
||||||
|
static uint8_t buf_usart3_rb_h2a[512];
|
||||||
|
|
||||||
|
static struct chx_intr usart2_intr;
|
||||||
|
static struct chx_intr usart3_intr;
|
||||||
|
|
||||||
|
static struct rng_rb usart2_rb_a2h;
|
||||||
|
static struct rng_rb usart2_rb_h2a;
|
||||||
|
static struct rng_rb usart3_rb_a2h;
|
||||||
|
static struct rng_rb usart3_rb_h2a;
|
||||||
|
|
||||||
|
static chopstx_poll_cond_t usart2_app_write_event;
|
||||||
|
static chopstx_poll_cond_t usart3_app_write_event;
|
||||||
|
|
||||||
|
static struct chx_poll_head * usart_poll[4];
|
||||||
|
|
||||||
|
static int usart2_tx_ready;
|
||||||
|
static int usart3_tx_ready;
|
||||||
|
|
||||||
|
static int
|
||||||
|
handle_intr (struct USART *USARTx, struct rng_rb rb2a, struct usart_stat *stat)
|
||||||
|
{
|
||||||
|
int tx_ready = 0;
|
||||||
|
uint32_t r = USARTx->SR;
|
||||||
|
|
||||||
|
if ((r & USART_SR_TXE))
|
||||||
|
{
|
||||||
|
tx_ready = 1;
|
||||||
|
USARTx->CR1 &= ~USART_CR1_TXEIE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((r & USART_SR_RXNE))
|
||||||
|
{
|
||||||
|
uint32_t data = USARTx->DR;
|
||||||
|
|
||||||
|
/* DR register should be accessed even if data is not used.
|
||||||
|
* Its read-access has side effect of clearing error flags.
|
||||||
|
*/
|
||||||
|
asm volatile ("" : : "r" (data) : "memory");
|
||||||
|
|
||||||
|
if ((r & USART_SR_NE))
|
||||||
|
stat->err_rx_noise++;
|
||||||
|
else if ((r & USART_SR_FE))
|
||||||
|
{
|
||||||
|
stat->rx_break++;
|
||||||
|
/* XXX: break event report to upper layer? */
|
||||||
|
}
|
||||||
|
else if ((r & USART_SR_PE))
|
||||||
|
stat->err_rx_parity++;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ((r & USART_SR_ORE))
|
||||||
|
stat->err_rx_overrun++;
|
||||||
|
|
||||||
|
if (rb_ll_put (rb2a, (data & 0xff)) < 0)
|
||||||
|
stat->err_rx_overflow++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return tx_ready;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
handle_tx_ready (struct USART *USARTx, struct rng_rb rb2h,
|
||||||
|
struct usart_stat *stat)
|
||||||
|
{
|
||||||
|
int c = rb_ll_get (rb2h);
|
||||||
|
|
||||||
|
if (c >= 0)
|
||||||
|
{
|
||||||
|
USARTx->DR = c;
|
||||||
|
USARTx->CR1 |= USART_CR1_TXEIE;
|
||||||
|
stat->tx++;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *
|
||||||
|
usart_main (void *arg)
|
||||||
|
{
|
||||||
|
(void)arg;
|
||||||
|
|
||||||
|
usart2_tx_ready = 1;
|
||||||
|
usart3_tx_ready = 1;
|
||||||
|
|
||||||
|
chopstx_claim_irq (&usart2_intr, INTR_REQ_USART2);
|
||||||
|
chopstx_claim_irq (&usart3_intr, INTR_REQ_USART3);
|
||||||
|
|
||||||
|
rb_init (&usart2_rb_a2h, buf_usart2_rb_a2h, sizeof buf_usart2_rb_a2h);
|
||||||
|
rb_init (&usart2_rb_h2a, buf_usart2_rb_h2a, sizeof buf_usart2_rb_h2a);
|
||||||
|
rb_init (&usart3_rb_a2h, buf_usart3_rb_a2h, sizeof buf_usart3_rb_a2h);
|
||||||
|
rb_init (&usart3_rb_h2a, buf_usart3_rb_h2a, sizeof buf_usart3_rb_h2a);
|
||||||
|
|
||||||
|
rb_get_prepare_poll (&usart2_rb_a2h, &usart2_app_write_event);
|
||||||
|
rb_get_prepare_poll (&usart3_rb_a2h, &usart3_app_write_event);
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
int n = 0;
|
||||||
|
|
||||||
|
usart_poll[n++] = &usart2_intr;
|
||||||
|
usart_poll[n++] = &usart3_intr;
|
||||||
|
if (usart2_tx_ready)
|
||||||
|
usart_poll[n++] = &usart2_app_write_event;
|
||||||
|
else
|
||||||
|
usart2_app_write_event.ready = 0;
|
||||||
|
if (usart3_tx_ready)
|
||||||
|
usart_poll[n++] = &usart3_app_write_event;
|
||||||
|
else
|
||||||
|
usart3_app_write_event.ready = 0;
|
||||||
|
|
||||||
|
chopstx_poll (NULL, n, usart_poll);
|
||||||
|
|
||||||
|
if (usart2_intr.ready)
|
||||||
|
usart2_tx_ready = handle_intr (USART2, &usart2_rb_h2a, &usart2_stat);
|
||||||
|
|
||||||
|
if (usart3_intr.ready)
|
||||||
|
usart3_tx_ready = handle_intr (USART3, &usart3_rb_h2a, &usart3_stat);
|
||||||
|
|
||||||
|
if (usart2_tx_ready && usart2_app_write_event.ready)
|
||||||
|
usart2_tx_ready = handle_tx_ready (USART2,
|
||||||
|
&usart2_rb_a2h, &usart2_stat);
|
||||||
|
|
||||||
|
if (usart3_tx_ready && usart3_app_write_event.ready)
|
||||||
|
usart3_tx_ready = handle_tx_ready (USART3,
|
||||||
|
&usart3_rb_a2h, &usart3_stat);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user