- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
There are more than a hundred ways to skin a cat and I can see that there might be many more incorrect ways to code RX-ing bytes with the Cypress PSOC 4200 SCB UART.
I have another processor Tx-ing exactly 48 bytes to the PSOC 4200 RX pin at 115200 baud every few seconds.
I can't find any example on the web that shows how to receive multiple bytes by the Standard UART, I can find only a far too simple video that shows how to echo each byte received back to the sending terminal.
I have use of only one UART, alias UA, RX only mode.
I have started the UART in main() correctly before the main() loop.
I have a char buffer Rx[48] to hold the receive bytes and the PSOC baudrate=115200,N,8,1 as well,
I have set the UART circular buffer RX FIFO buffer size to 48 bytes.
The only active interrupts I have selected: RX FIFO buffer full, FIFO Overflow, Frame Error
I have come up with the code below.
Will this seemingly too simple code work and also robust enough to deal with possible various RX receive errors?
//var initialization before main()
static char Rx[48];
static char j;
// in main()
if(UA_CHECK_CAUSE_INTR(UA_INTR_RX_FULL))
{
for(j=0;j<48;j++)
{ Rx
}
UA_rx_ClearInterrupt();
}
else if(UA_CHECK_CAUSE_INTR(UA_INTR_RX_ALL))
{
UA_rx_ClearInterrupt();
UA_Stop();
UA_Start();
}
Solved! Go to Solution.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi,
> There are more than a hundred ways to skin a cat and I can see that there might be many more incorrect ways to code RX-ing bytes with the Cypress PSOC 4200 SCB UART.
I agree, although I'm going to adopt a cat next week instead of skinning one,
in general serial communication is not an easy beast especially when you are on the receiving side.
Although I'm not a one from Cypress, considering the flexibility of module configuration of PSoC, preparing documents for all possible configuration should be very difficult if not impossible. So the datasheet seems to provide only "general" descriptions and often (or usually?) we have to read the headers (and sources) in the Generated_Source to know what kind of APIs were generated and available. (The APIs, arguments are often different between versions and/or devices, which makes the story even challenging)
Reading your first message, I could not think of a strategy without any ISRs, as, IMHO, most likely happening error/trouble would be "timeout".
Anyway, so I tried my exercise.
To test the program I wrote a couple of programs, one for TX side and the other is for RX side.
By any mean I do not claim that my program is perfect nor elegant but it's the way I ski[BS][BS] adopt a cat 😉
TX side sends data in 4 different mode,
mode 0: 48 bytes at once (A...v)
mode 1: 48 bytes by byte by byte (B..w)
mode 2: 20 bytes and wait a few seconds to trigger time out (a..t)
mode 3: 60 bytes to try over run.. but could not cause over run (K..=)
TX side wait for a rx data and read up to PACKET_SIZE(=48) then shows received string.
Meantime for Mode 2 successfully detect time out, but over run did not happen and
the first 48 letters were reported.
main.c of TX side
===================
#include "project.h"
#include <stdio.h>
#define USE_UA 1
char str[128] ; /* print buffer */
uint8_t data[] = {
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', /* 10 */
'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', /* 20 */
'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', /* 30 */
'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', /* 40 */
'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', /* 50 */
'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', /* 60 */
'8', '9', '!', '#', '$', '(', ')', '*', '+', '=' /* 70 */
} ;
void init_hardware(void)
{
CyGlobalIntEnable; /* Enable global interrupts. */
UART_Start() ;
#if USE_UA
UA_TX_Start() ;
#endif
}
void send_48bytes(void) /* A ~ v */
{
#if USE_UA
UA_TX_SpiUartPutArray(data, 48);
#else
UART_SpiUartPutArray(data, 48);
#endif
}
void send_48_one_by_one(void) /* B ~ w */
{
int i ;
for (i = 0 ; i < 48 ; i++ ) {
#if USE_UA
UA_TX_UartPutChar(data[i+1]) ;
#else
UART_UartPutChar(data) ;
#endif
}
}
void send_less(void) /* a ~ t */
{
#if USE_UA
UA_TX_SpiUartPutArray(&data[26], 20) ;
#else
UART_SpiUartPutArray(data, 20);
#endif
}
void send_more(void) /* K ~ */
{
#if USE_UA
UA_TX_SpiUartPutArray(&data[10], 60) ;
#else
UART_SpiUartPutArray(data, 60);
#endif
}
int main(void)
{
int interval = 3000 ; /* interval seconds x 1000 */
int mode = 0 ;
init_hardware() ;
sprintf(str, "UART TX test (%s %s)\n", __DATE__, __TIME__) ;
UART_UartPutString(str) ;
while(1) {
sprintf(str, "Mode %d:", mode) ;
UART_UartPutString(str) ;
switch(mode) {
case 0: /* send normal 48 bytes */
send_48bytes() ;
break ;
case 1: /* send normal 48 bytes, one by one */
send_48_one_by_one() ;
break ;
case 2: /* send only 20 bytes not enough bytes */
send_less() ;
CyDelay(6000) ;
break ;
case 3: /* send 60 bytes (too many bytes) */
send_more() ;
break ;
default:
break ;
}
UART_UartPutString("\n") ;
mode = (mode + 1) % 4 ; /* 0 ~ 3 */
CyDelay(interval) ;
}
}
===================
main.c of RX side (I think that this really is clumsy)
===================
#include "project.h"
#include <stdio.h>
#define VERBOS 0
#define ST_IDLE 0
#define ST_RECEIVING 1
#define ST_TIMEOUT 2
#define ST_RX_ERROR 3
#define PACKET_SIZE 48
char str[128] ; /* print buffer */
char data[PACKET_SIZE + 1] ; /* one for null */
int status = ST_IDLE;
int prev_status = ST_IDLE ;
int data_valid = 0 ;
int num_received = 0 ;
void set_status(int next_status)
{
prev_status = status ;
status = next_status ;
}
/**
* timer_isr
* If this isr is called
* that means a timeout occured for transaction
*/
CY_ISR(timer_isr)
{
Timer_INT_Disable() ;
Timer_INT_ClearPending() ;
Timer_Stop() ;
Timer_WriteCounter(0) ;
UA_Stop() ;
status = ST_TIMEOUT ;
data_valid = 0 ;
}
void start_alarm(uint32_t timeout)
{
Timer_INT_StartEx(timer_isr) ;
Timer_WriteCounter(0) ; /* clear the counter */
Timer_WriteCompare(timeout) ; /* timeout period */
Timer_Start() ;
}
void stop_alarm(void)
{
Timer_Stop() ;
Timer_WriteCounter(0) ;
Timer_INT_Disable() ;
Timer_INT_ClearPending() ;
}
/**
* UA_isr()
*/
CY_ISR(UA_isr)
{
if (UA_CHECK_INTR_RX(UA_INTR_RX_ERR)) {
UA_Stop() ;
set_status(ST_RX_ERROR) ;
} else if (status == ST_IDLE) {
if (UA_SpiUartGetRxBufferSize() > 0){
set_status(ST_RECEIVING) ;
}
}
UA_ClearPendingInt() ;
}
void init_hardware(void)
{
CyGlobalIntEnable; /* Enable global interrupts. */
UART_Start() ;
UA_SpiUartClearRxBuffer() ;
UA_Start() ;
UA_SetCustomInterruptHandler(UA_isr);
}
int main(void)
{
int i ;
init_hardware() ;
sprintf(str, "UART RX test (%s %s)\n", __DATE__, __TIME__) ;
UART_UartPutString(str) ;
while(1) {
#if VERBOS
if (status != prev_status) {
switch(status) {
case ST_IDLE: UART_UartPutString("ST_IDLE\n") ; break ;
case ST_RECEIVING: UART_UartPutString("ST_RECEIVING\n") ; break ;
case ST_TIMEOUT: UART_UartPutString("ST_TIMEOUT\n") ; break ;
case ST_RX_ERROR: UART_UartPutString("ST_RX_ERROR\n") ; break ;
}
}
#endif
switch(status) {
case ST_TIMEOUT:
sprintf(str, "Error timeout at %d char: ", num_received) ;
UART_UartPutString(str) ;
if (num_received > 0) {
for (i = 0 ; i < num_received ; i++ ) {
data = UA_UartGetChar() ;
}
data[num_received] = 0 ;
UART_UartPutString(data) ;
}
UART_UartPutString("\n") ;
UA_SpiUartClearRxBuffer() ;
num_received = 0 ;
data_valid = 0 ;
set_status(ST_IDLE) ;
break ;
case ST_RX_ERROR:
sprintf(str, "Error UA RX error: ") ;
UART_UartPutString(str) ;
if (num_received > 0) {
for (i = 0 ; i > num_received ; i++ ) {
data = UA_UartGetChar() ;
}
data[num_received] = 0 ;
UART_UartPutString(data) ;
}
UART_UartPutString("\n") ;
UA_SpiUartClearRxBuffer() ;
num_received = 0 ;
data_valid = 0 ;
set_status(ST_IDLE) ;
break ;
case ST_IDLE:
if (data_valid) {
UART_UartPutString("OK: ") ;
UART_UartPutString(data) ;
UART_UartPutString("\n") ;
UA_SpiUartClearRxBuffer() ;
}
if (prev_status != ST_IDLE) {
num_received = 0 ;
data_valid = 0 ;
UA_SpiUartClearRxBuffer() ;
UA_Start() ;
// num_received = 0 ;
// data_valid = 0 ;
#if VERBOS
UART_UartPutString("Alarm Clear!\n") ;
#endif
stop_alarm() ;
}
set_status(ST_IDLE) ;
break ;
case ST_RECEIVING:
if (prev_status == ST_IDLE) {
#if VERBOS
UART_UartPutString("Alarm Set!\n") ;
#endif
start_alarm(50) ;
}
num_received = UA_SpiUartGetRxBufferSize() ;
if (num_received == PACKET_SIZE) {
stop_alarm() ;
for (i = 0 ; i < PACKET_SIZE; i++ ) {
data = UA_UartGetChar() ;
}
data = 0 ; /* terminate c-string */
data_valid = 1 ;
set_status(ST_IDLE) ;
} else if (num_received > PACKET_SIZE) {
UART_UartPutString("Data Over Run\n") ;
stop_alarm() ;
set_status(ST_IDLE) ;
} else {
set_status(ST_RECEIVING) ;
}
break ;
}
CyDelay(10) ;
}
}
===================
moto
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi Richard,
Your way of achieving the goal looks fine. Here , I can suggest one another way without having any of the interrupts enabled.
Select RX buffer size => 48 bytes.
Use below pseudo code snippet.
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
static char Rx[48];
static char i;
for(;;)
{
if (SCB_SpiUartGetRxBufferSize()==48)
{
for ( i=0; i <48;i++ )
{
Rx=SCB_UartGetByte();
}
}
}
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-Gyan
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thank you Gyan, I was beginning to think no one would reply!
In writing code, there must exist some clear documentation to disambiguate API function arguments to avoid dangerous coding bugs that are due to unavoidable confusion when a programmer encounters a long list of of seemingly undocumented UART arguments..
In particular, in my code example, the API's in the Standard UART datasheet doesn't mention the coding choices I've used.
How can anyone learn to precise the use of so many arguments that are seemingly undocumented in the UART datasheet to be sure that they are options available and being properly used, when there is seemingly no explanation presented to precise the what, why, and when(and not when) of their use, yet these choices appear in the very long drop down list as suggestions when entering arguments for the Standard UART API events and methods?
What is also odd, that some possible arguments for methods have lower case "rx" in them, yet some have "RX" in them? What is the meaning behind this inconsistency, why so many many choices that have no elaboration or documentation? Are some deprecated or favored or have caveats?
In any case, I don't quite understand, how does your code detect and fix possible UART receive errors, such as frame errors, buffer overflow?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi,
> There are more than a hundred ways to skin a cat and I can see that there might be many more incorrect ways to code RX-ing bytes with the Cypress PSOC 4200 SCB UART.
I agree, although I'm going to adopt a cat next week instead of skinning one,
in general serial communication is not an easy beast especially when you are on the receiving side.
Although I'm not a one from Cypress, considering the flexibility of module configuration of PSoC, preparing documents for all possible configuration should be very difficult if not impossible. So the datasheet seems to provide only "general" descriptions and often (or usually?) we have to read the headers (and sources) in the Generated_Source to know what kind of APIs were generated and available. (The APIs, arguments are often different between versions and/or devices, which makes the story even challenging)
Reading your first message, I could not think of a strategy without any ISRs, as, IMHO, most likely happening error/trouble would be "timeout".
Anyway, so I tried my exercise.
To test the program I wrote a couple of programs, one for TX side and the other is for RX side.
By any mean I do not claim that my program is perfect nor elegant but it's the way I ski[BS][BS] adopt a cat 😉
TX side sends data in 4 different mode,
mode 0: 48 bytes at once (A...v)
mode 1: 48 bytes by byte by byte (B..w)
mode 2: 20 bytes and wait a few seconds to trigger time out (a..t)
mode 3: 60 bytes to try over run.. but could not cause over run (K..=)
TX side wait for a rx data and read up to PACKET_SIZE(=48) then shows received string.
Meantime for Mode 2 successfully detect time out, but over run did not happen and
the first 48 letters were reported.
main.c of TX side
===================
#include "project.h"
#include <stdio.h>
#define USE_UA 1
char str[128] ; /* print buffer */
uint8_t data[] = {
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', /* 10 */
'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', /* 20 */
'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', /* 30 */
'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', /* 40 */
'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', /* 50 */
'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', /* 60 */
'8', '9', '!', '#', '$', '(', ')', '*', '+', '=' /* 70 */
} ;
void init_hardware(void)
{
CyGlobalIntEnable; /* Enable global interrupts. */
UART_Start() ;
#if USE_UA
UA_TX_Start() ;
#endif
}
void send_48bytes(void) /* A ~ v */
{
#if USE_UA
UA_TX_SpiUartPutArray(data, 48);
#else
UART_SpiUartPutArray(data, 48);
#endif
}
void send_48_one_by_one(void) /* B ~ w */
{
int i ;
for (i = 0 ; i < 48 ; i++ ) {
#if USE_UA
UA_TX_UartPutChar(data[i+1]) ;
#else
UART_UartPutChar(data) ;
#endif
}
}
void send_less(void) /* a ~ t */
{
#if USE_UA
UA_TX_SpiUartPutArray(&data[26], 20) ;
#else
UART_SpiUartPutArray(data, 20);
#endif
}
void send_more(void) /* K ~ */
{
#if USE_UA
UA_TX_SpiUartPutArray(&data[10], 60) ;
#else
UART_SpiUartPutArray(data, 60);
#endif
}
int main(void)
{
int interval = 3000 ; /* interval seconds x 1000 */
int mode = 0 ;
init_hardware() ;
sprintf(str, "UART TX test (%s %s)\n", __DATE__, __TIME__) ;
UART_UartPutString(str) ;
while(1) {
sprintf(str, "Mode %d:", mode) ;
UART_UartPutString(str) ;
switch(mode) {
case 0: /* send normal 48 bytes */
send_48bytes() ;
break ;
case 1: /* send normal 48 bytes, one by one */
send_48_one_by_one() ;
break ;
case 2: /* send only 20 bytes not enough bytes */
send_less() ;
CyDelay(6000) ;
break ;
case 3: /* send 60 bytes (too many bytes) */
send_more() ;
break ;
default:
break ;
}
UART_UartPutString("\n") ;
mode = (mode + 1) % 4 ; /* 0 ~ 3 */
CyDelay(interval) ;
}
}
===================
main.c of RX side (I think that this really is clumsy)
===================
#include "project.h"
#include <stdio.h>
#define VERBOS 0
#define ST_IDLE 0
#define ST_RECEIVING 1
#define ST_TIMEOUT 2
#define ST_RX_ERROR 3
#define PACKET_SIZE 48
char str[128] ; /* print buffer */
char data[PACKET_SIZE + 1] ; /* one for null */
int status = ST_IDLE;
int prev_status = ST_IDLE ;
int data_valid = 0 ;
int num_received = 0 ;
void set_status(int next_status)
{
prev_status = status ;
status = next_status ;
}
/**
* timer_isr
* If this isr is called
* that means a timeout occured for transaction
*/
CY_ISR(timer_isr)
{
Timer_INT_Disable() ;
Timer_INT_ClearPending() ;
Timer_Stop() ;
Timer_WriteCounter(0) ;
UA_Stop() ;
status = ST_TIMEOUT ;
data_valid = 0 ;
}
void start_alarm(uint32_t timeout)
{
Timer_INT_StartEx(timer_isr) ;
Timer_WriteCounter(0) ; /* clear the counter */
Timer_WriteCompare(timeout) ; /* timeout period */
Timer_Start() ;
}
void stop_alarm(void)
{
Timer_Stop() ;
Timer_WriteCounter(0) ;
Timer_INT_Disable() ;
Timer_INT_ClearPending() ;
}
/**
* UA_isr()
*/
CY_ISR(UA_isr)
{
if (UA_CHECK_INTR_RX(UA_INTR_RX_ERR)) {
UA_Stop() ;
set_status(ST_RX_ERROR) ;
} else if (status == ST_IDLE) {
if (UA_SpiUartGetRxBufferSize() > 0){
set_status(ST_RECEIVING) ;
}
}
UA_ClearPendingInt() ;
}
void init_hardware(void)
{
CyGlobalIntEnable; /* Enable global interrupts. */
UART_Start() ;
UA_SpiUartClearRxBuffer() ;
UA_Start() ;
UA_SetCustomInterruptHandler(UA_isr);
}
int main(void)
{
int i ;
init_hardware() ;
sprintf(str, "UART RX test (%s %s)\n", __DATE__, __TIME__) ;
UART_UartPutString(str) ;
while(1) {
#if VERBOS
if (status != prev_status) {
switch(status) {
case ST_IDLE: UART_UartPutString("ST_IDLE\n") ; break ;
case ST_RECEIVING: UART_UartPutString("ST_RECEIVING\n") ; break ;
case ST_TIMEOUT: UART_UartPutString("ST_TIMEOUT\n") ; break ;
case ST_RX_ERROR: UART_UartPutString("ST_RX_ERROR\n") ; break ;
}
}
#endif
switch(status) {
case ST_TIMEOUT:
sprintf(str, "Error timeout at %d char: ", num_received) ;
UART_UartPutString(str) ;
if (num_received > 0) {
for (i = 0 ; i < num_received ; i++ ) {
data = UA_UartGetChar() ;
}
data[num_received] = 0 ;
UART_UartPutString(data) ;
}
UART_UartPutString("\n") ;
UA_SpiUartClearRxBuffer() ;
num_received = 0 ;
data_valid = 0 ;
set_status(ST_IDLE) ;
break ;
case ST_RX_ERROR:
sprintf(str, "Error UA RX error: ") ;
UART_UartPutString(str) ;
if (num_received > 0) {
for (i = 0 ; i > num_received ; i++ ) {
data = UA_UartGetChar() ;
}
data[num_received] = 0 ;
UART_UartPutString(data) ;
}
UART_UartPutString("\n") ;
UA_SpiUartClearRxBuffer() ;
num_received = 0 ;
data_valid = 0 ;
set_status(ST_IDLE) ;
break ;
case ST_IDLE:
if (data_valid) {
UART_UartPutString("OK: ") ;
UART_UartPutString(data) ;
UART_UartPutString("\n") ;
UA_SpiUartClearRxBuffer() ;
}
if (prev_status != ST_IDLE) {
num_received = 0 ;
data_valid = 0 ;
UA_SpiUartClearRxBuffer() ;
UA_Start() ;
// num_received = 0 ;
// data_valid = 0 ;
#if VERBOS
UART_UartPutString("Alarm Clear!\n") ;
#endif
stop_alarm() ;
}
set_status(ST_IDLE) ;
break ;
case ST_RECEIVING:
if (prev_status == ST_IDLE) {
#if VERBOS
UART_UartPutString("Alarm Set!\n") ;
#endif
start_alarm(50) ;
}
num_received = UA_SpiUartGetRxBufferSize() ;
if (num_received == PACKET_SIZE) {
stop_alarm() ;
for (i = 0 ; i < PACKET_SIZE; i++ ) {
data = UA_UartGetChar() ;
}
data = 0 ; /* terminate c-string */
data_valid = 1 ;
set_status(ST_IDLE) ;
} else if (num_received > PACKET_SIZE) {
UART_UartPutString("Data Over Run\n") ;
stop_alarm() ;
set_status(ST_IDLE) ;
} else {
set_status(ST_RECEIVING) ;
}
break ;
}
CyDelay(10) ;
}
}
===================
moto
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thank you much for your efforts!.
But, you wrote your own complicated program for the UART,(again,many thanks for the effort) but you didn't attempt to test my code, and yet you failed to attain a buffer overflow error?
The point I'm trying to make in my posting is that there should be better, more exhaustive, more helpful documentation, including code examples.
At the least, any programmer doing meaningful work (not just toying around) would wish for is an example in C that simply shows how to accomplish common uses of the component available for use, i.e, my likely very common way to use the Standard UART component to enable UART RX..
Good coding should not create a "House of Cards" that can be crashed by some unexpected event. As a programmer, I am not playing with Legos, I am engaging in serious work that demands I am able to quickly and easily acquire the knowledge to I need to achieve a robust understanding of just how things(components) work. Only in this way can I begin to hope to code a bug-free result.
No one can make a living coding by only knowing how to echo bytes from a terminal, and this seems to be the only tutoring offered
Having no code means I am going hungry, and my employer, Ebineezer S. will not pay me for sloppy work, so the cat is beginning to look like the main course of my Xmas dinner and poor Tiny T. will not walk again..
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
OK, first of all please allow me for my sloppy code as my carrier has been Lab guy and/or prototype design/developer.
There may be documents you are asking for but I have not found one.
Anyway, if I'll be allowed to touch the code you post, I would
===========================
if(UA_CHECK_CAUSE_INTR(UA_INTR_RX_FULL)) {
for(j=0;j<48;j++) {
Rx
}
UA_rx_ClearInterrupt();
} else if(UA_CHECK_CAUSE_INTR(UA_INTR_RX_ALL)) {
UA_rx_ClearInterrupt();
UA_Stop();
UA_Init(); /* re-initialize UA refer to the comment UA.c line 77- */
UA_Start(); /* UA_Start does not initialize for the 2nd time */
}
===========================
Note: the code's line number may be different for each system,
but I hope at least fine name should be the same.
moto