Skip to content

Commit

Permalink
Merge pull request #11612 from ben-postman/pr_cc26x0_uart_mode
Browse files Browse the repository at this point in the history
cpu/cc26x0: implement uart_mode()
  • Loading branch information
MrKevinWeiss committed Jun 6, 2019
2 parents cca2031 + 567fa8e commit 002e033
Show file tree
Hide file tree
Showing 7 changed files with 309 additions and 3 deletions.
2 changes: 2 additions & 0 deletions cpu/cc26x0/Makefile.features
@@ -1,3 +1,5 @@
FEATURES_PROVIDED += periph_cpuid
FEATURES_PROVIDED += periph_uart
FEATURES_PROVIDED += periph_uart_modecfg

-include $(RIOTCPU)/cortexm_common/Makefile.features
5 changes: 2 additions & 3 deletions cpu/cc26x0/include/cc26x0_uart.h
Expand Up @@ -72,9 +72,8 @@ typedef struct {
#define UART_FR_RXFF 0x40
#define UART_FR_TXFE 0x80

#define UART_LCRH_PEN 0x1
#define UART_LCRH_EPS 0x2
#define UART_LCRH_RXFE 0x4
#define UART_LCRH_PEN 0x2
#define UART_LCRH_EPS 0x4
#define UART_LCRH_STP2 0x8
#define UART_LCRH_FEN 0x10
#define UART_LCRH_WLEN_mask 0x60
Expand Down
47 changes: 47 additions & 0 deletions cpu/cc26x0/include/periph_cpu.h
Expand Up @@ -65,6 +65,53 @@ typedef enum {
GPIO_BOTH = IOCFG_EDGEDET_BOTH
} gpio_flank_t;

/*
* @brief Invalid UART mode mask
*
* This mask is also used to force data_bits_t to be uint32_t type
* since it may be assigned a uint32_t variable in uart_mode
*/
#define UART_INVALID_MODE (0x8000000)

/**
* @brief Override parity values
* @{
*/
#define HAVE_UART_PARITY_T
typedef enum {
UART_PARITY_NONE = 0,
UART_PARITY_EVEN = (UART_LCRH_PEN | UART_LCRH_EPS),
UART_PARITY_ODD = UART_LCRH_PEN,
UART_PARITY_MARK = UART_INVALID_MODE | 4,
UART_PARITY_SPACE = UART_INVALID_MODE | 5
} uart_parity_t;
/** @} */

/**
* @brief Override data bits length values
* @{
*/
#define HAVE_UART_DATA_BITS_T
typedef enum {
UART_DATA_BITS_5 = UART_LCRH_WLEN_5,
UART_DATA_BITS_6 = UART_LCRH_WLEN_6,
UART_DATA_BITS_7 = UART_LCRH_WLEN_7,
UART_DATA_BITS_8 = UART_LCRH_WLEN_8
} uart_data_bits_t;
/** @} */

/**
* @brief Override stop bits length values
* @{
*/
#define HAVE_UART_STOP_BITS_T
typedef enum {
UART_STOP_BITS_1 = 0,
UART_STOP_BITS_2 = UART_LCRH_STP2,
} uart_stop_bits_t;
/** @} */


/**
* @brief Configuration of low-level general purpose timers
*
Expand Down
42 changes: 42 additions & 0 deletions cpu/cc26x0/periph/uart.c
Expand Up @@ -21,6 +21,7 @@

#include "cpu.h"
#include "periph/uart.h"
#include "periph_conf.h"

/**
* @brief Bit mask for the fractional part of the baudrate
Expand Down Expand Up @@ -91,6 +92,47 @@ int uart_init(uart_t uart, uint32_t baudrate, uart_rx_cb_t rx_cb, void *arg)
return UART_OK;
}


#ifdef MODULE_PERIPH_UART_MODECFG
int uart_mode(uart_t uart, uart_data_bits_t data_bits, uart_parity_t parity,
uart_stop_bits_t stop_bits)
{
assert(data_bits == UART_DATA_BITS_5 ||
data_bits == UART_DATA_BITS_6 ||
data_bits == UART_DATA_BITS_7 ||
data_bits == UART_DATA_BITS_8);

assert(parity == UART_PARITY_NONE ||
parity == UART_PARITY_EVEN ||
parity == UART_PARITY_ODD ||
parity == UART_PARITY_MARK ||
parity == UART_PARITY_SPACE);

assert(stop_bits == UART_STOP_BITS_1 ||
stop_bits == UART_STOP_BITS_2);

/* make sure the uart device is valid */
if (uart != 0) {
return UART_NODEV;
}

/* cc26x0 does not support mark or space parity */
if (parity == UART_PARITY_MARK || parity == UART_PARITY_SPACE) {
return UART_NOMODE;
}

/* Disable UART and clear old settings */
UART->CTL = 0;
UART->LCRH = 0;

/* Apply setting and enable UART */
UART->LCRH = data_bits | parity | stop_bits;
UART->CTL = ENABLE_MASK;

return UART_OK;
}
#endif

void uart_write(uart_t uart, const uint8_t *data, size_t len)
{
(void) uart;
Expand Down
14 changes: 14 additions & 0 deletions tests/periph_uart_mode/Makefile
@@ -0,0 +1,14 @@
include ../Makefile.tests_common

BOARD_INSUFFICIENT_MEMORY := arduino-duemilanove arduino-leonardo arduino-nano\
arduino-uno nucleo-f031k6

FEATURES_REQUIRED += periph_uart
FEATURES_REQUIRED += periph_uart_modecfg

USEMODULE += xtimer

# Set this to prevent welcome message from printing and confusing output
CFLAGS+=-DLOG_LEVEL=LOG_NONE

include $(RIOTBASE)/Makefile.include
22 changes: 22 additions & 0 deletions tests/periph_uart_mode/README.md
@@ -0,0 +1,22 @@
Expected result
===============

Use a probe to examine the output from the UART. It tests all
permutations of data-bits, parity, and stop-bits. For each mode, the mode
configuration will be printed to STDOUT as:
<data-bits><parity-bits><stop-bits>
For example: 7 data-bits, even parity, and 2 stop-bits would be: 7E2
Only supported mode strings will be printed out. At the end of the
test, the default mode will be restored, and a list indicating which
modes were supported and unsupported by the device. The scope still
needs to be used to validate that the settings were applied properly.
If a different BAUD rate than 115200 is desired, compile with:
`CFLAGS+=-DSTDIO_UART_BAUDRATE=<BAUD>`

Background
==========

This test was created because the existing periph_uart test relies on the
presence of multiple UARTs, so that one can be used for the shell, and another
for testing. This test requires no shell hookup, and automatically runs through
the test procedure, relying on a probe to examine the results.
180 changes: 180 additions & 0 deletions tests/periph_uart_mode/main.c
@@ -0,0 +1,180 @@
/*
* Copyright (C) 2018 Sparkmeter
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/

/**
* @ingroup tests
* @{
*
* @file
* @brief Manual test application for UART mode on CPUs with only one UART
*
* @author Ben Postman <ben.l.postman@gmail.com>
*
* @}
*/

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#include "periph/uart.h"
#include "stdio_uart.h"
#include "xtimer.h"

/* Number of different options for each mode parameter */
#define DATA_BIT_OPTIONS (4)
#define PARITY_OPTIONS (5)
#define STOP_BIT_OPTIONS (2)
#define TOTAL_OPTIONS (DATA_BIT_OPTIONS * PARITY_OPTIONS * STOP_BIT_OPTIONS)

/* Character positions in the mode string */
#define DATA_BIT_POS (0)
#define PARITY_POS (1)
#define STOP_BIT_POS (2)

/* Length of the printable mode string, includes null terminator */
#define MODE_STR_LEN (4)

/* UART_DEV is always 0 since this test is for device with 1 UART */
#define _UART_DEV (UART_DEV(0))

/* Delay between each mode, makes parsing results easier */
#ifndef DELAY_US
#define DELAY_US 50000
#endif


/* Stores each mode string for printing at the end of the test */
static char mode_strings[TOTAL_OPTIONS][MODE_STR_LEN];


static void _get_mode(const uart_data_bits_t data_bits,
const uart_parity_t parity, const uart_stop_bits_t stop_bits, char* mode_str) {
switch (data_bits) {
case UART_DATA_BITS_5:
mode_str[DATA_BIT_POS] = '5';
break;
case UART_DATA_BITS_6:
mode_str[DATA_BIT_POS] = '6';
break;
case UART_DATA_BITS_7:
mode_str[DATA_BIT_POS] = '7';
break;
case UART_DATA_BITS_8:
mode_str[DATA_BIT_POS] = '8';
break;
default:
break;
}

switch (parity) {
case UART_PARITY_NONE:
mode_str[PARITY_POS] = 'N';
break;
case UART_PARITY_EVEN:
mode_str[PARITY_POS] = 'E';
break;
case UART_PARITY_ODD:
mode_str[PARITY_POS] = 'O';
break;
case UART_PARITY_MARK:
mode_str[PARITY_POS] = 'M';
break;
case UART_PARITY_SPACE:
mode_str[PARITY_POS] = 'S';
break;
default:
break;
}

switch (stop_bits) {
case UART_STOP_BITS_1:
mode_str[STOP_BIT_POS] = '1';
break;
case UART_STOP_BITS_2:
mode_str[STOP_BIT_POS] = '2';
break;
default:
break;
}

mode_str[MODE_STR_LEN - 1] = '\0';
}


int main(void)
{
int8_t status;

/* Stores the result for each mode */
bool results[TOTAL_OPTIONS];

/* Results index that is used to associate mode_strings and results */
uint8_t ridx = 0;

/* Use arrays so that each option can be easily iterated over */
const uart_data_bits_t data_bits[DATA_BIT_OPTIONS] = {
UART_DATA_BITS_5,
UART_DATA_BITS_6,
UART_DATA_BITS_7,
UART_DATA_BITS_8
};

const uart_parity_t parity[PARITY_OPTIONS] = {
UART_PARITY_NONE,
UART_PARITY_EVEN,
UART_PARITY_ODD,
UART_PARITY_MARK,
UART_PARITY_SPACE
};

const uart_stop_bits_t stop_bits[STOP_BIT_OPTIONS] = {
UART_STOP_BITS_1,
UART_STOP_BITS_2
};

/* Test each permutation */
for (int didx = 0; didx < 4; ++didx) {
for (int pidx = 0; pidx < 5; ++pidx) {
for (int sidx = 0; sidx < 2; ++sidx) {
/* Initialize stdio to get printf */
stdio_init();

status = uart_mode(_UART_DEV, data_bits[didx],
parity[pidx], stop_bits[sidx]);
_get_mode(data_bits[didx], parity[pidx],
stop_bits[sidx], mode_strings[ridx]);

if (status == UART_OK) {
results[ridx] = true;
printf("%s\n", mode_strings[ridx]);
xtimer_usleep(DELAY_US);
}
else {
results[ridx] = false;
}

ridx++;
}
}
}

/* Reset mode and print results */
stdio_init();
uart_mode(_UART_DEV, UART_DATA_BITS_8, UART_PARITY_NONE, UART_STOP_BITS_1);
for (int i = 0; i < TOTAL_OPTIONS; ++i) {
if (results[i] == true) {
printf("%s: Supported\n", mode_strings[i]);
}
else {
printf("%s: Unsupported\n", mode_strings[i]);
}
}

return 0;
}

0 comments on commit 002e033

Please sign in to comment.