Bitshift in USART RS-232 communcation for SAM4S Xplained Pro

Go To Last Post
6 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi All!

 

I am fairly new to 32bit microprocessors. I have been struggling with the USART communication (RS-232) on my SAM4S Xplained pro board for some time. Today I was able to receive the same bytes I intend to send with a little extra steps I want to get rid of.

 

Following an instruction for USART1 (http://embedntks.com/sam4s-uart-and-usart/) I was able start up a communication with the board itself. It was working fine, transfer and receive byte was matching. This test however doesnt verify the Baud-rate and right arrangement of bits.

 

0xCA over RS-232

Oscilloscope reading of 0xCA byte over RS232. 0b11001010 is formatted to (H)HLHLHHLL(L) where (X) are start and stop bits. Note LSB first and inverted logic level.

 

When connecting to my laptop with an RS-232 converter I saw in Putty that the bytes were quite wrong. After some testing I have realised that the data bits are converted between the SAM4S and the PC (both Putty and other terminal program).

 

For example my output was 0b0100_0001 (0x41, 'A') while my reading is 0b0101_1111 (0x5F, '_'). The conversion steps are for ASCII codes:

1) Bitwise inversion

2A) 1 Bitwise shift to the right if ASCII code is ODD

2B) 2 Bitwise shift to the right if ASCII code is EVEN

 

I was able to confirm this with all (6+) chars I tested. The bitwise shift puts a 0 on the leftmost bits, which is an issue for the EVEN bytes, becuase at least one 1 bit is lost.

 

putty_sam4s (34A34A7934A)

Putty readout of string "34A". Red marked part is echoed back after pressing 7,8 and 9 in a sequence. 8 has an EVEN character code.

 

 

Below you can see my code, which includes two functions to compensate for the bit-shift. They solve the usart_write issue for both ODD and EVEN characters and the usart_read issue for only ODD characters.

 

conf_usart.h

/*
 * conf_usart.h
 *
 * Created: 27-07-2018 15:50:40
 *  Author: iss
 */ 

#ifndef CONF_USART_H_
#define CONF_USART_H_
#include "../../Software Layer/Global.h"

#define USART_BAUDRATE		9600

/* IN conf_clock.h :
#define CONFIG_SYSCLK_SOURCE        SYSCLK_SRC_MAINCK_XTAL //12MHz
*/

extern void init_rs232(void);
extern void usart_spec_write(uint32_t byte);
extern void usart_spec_read(uint32_t *byte);

#endif /* CONF_USART_H_ */

conf_usart.c

/*
 * conf_usart.c
 *
 * Created: 27-07-2018 15:51:11
 *  Author: iss
 */ 

#include "conf_usart.h"

void init_rs232(void)
{
	const sam_usart_opt_t usart_rs232_settings = {
		USART_BAUDRATE,
		US_MR_CHRL_8_BIT,
		US_MR_PAR_NO,
		US_MR_NBSTOP_1_BIT,
		US_MR_CHMODE_NORMAL
	};
	//PA5 and PA6 are pins for USART0
	//PA21 and PA22 are pins for USART1 (RX and TX)
	//disable PIOA control of PA21 and PA22 and enable peripheral on pins PA21 and PA22
	REG_PIOA_PDR |= PIO_PDR_P21;
	REG_PIOA_PDR |= PIO_PDR_P22;
	//Select peripheral A
	REG_PIOA_ABCDSR &=  ~(PIO_ABCDSR_P21);
	REG_PIOA_ABCDSR &=  ~(PIO_ABCDSR_P22);
	sysclk_init();
	sysclk_enable_peripheral_clock(ID_USART1);

	//ASF documentation uses sysclk_get_main_hz(), however it halves the Baudrate
	usart_init_rs232(RS_USART, &usart_rs232_settings, sysclk_get_peripheral_hz());
	usart_enable_tx(RS_USART);
	usart_enable_rx(RS_USART);
		usart_enable_interrupt(RS_USART, US_IER_RXRDY);
		NVIC_EnableIRQ(USART1_IRQn);

}

//USART1 interrupt, echoes back received byte
void USART1_Handler(void){
	static uint8_t debugByte = 1;
	uint32_t dw_status = usart_get_status(USART1);
	if (dw_status & US_CSR_RXRDY) {
		uint32_t received_byte;

		usart_spec_read(&received_byte);

		if (debugByte == 0)		//blinker
		{
			REG_PIOC_SODR |= PIO_SODR_P23;
			debugByte = 1;
			} else {
			REG_PIOC_CODR |= PIO_CODR_P23;
			debugByte = 0;
		}

		usart_spec_write(received_byte);
	}
}

void usart_spec_write(uint32_t byte)
{
	byte = byte ^ 0xFF;		//bitwise inversion
	byte = ((byte << 1) | (byte >> 7)) & 0xFF;

	usart_write(RS_USART, byte);
}

void usart_spec_read(uint32_t *byte)
{
	uint32_t tempChar;
	usart_read(USART1, &tempChar);
	tempChar = tempChar ^ 0xFF;		//bitwise inversion
	*byte = ((tempChar << 1) | (tempChar >> 7)) & 0xFF;
}

main.c

/** MAIN file **/
#include <asf.h>
#include "../Software Layer/Global.h"

int main (void)
{
    board_init();
    uint8_t debugByte = 1;
    wdt_disable(WDT);

    while (1) {
        delayMilli(2000);

        if (debugByte == 0)
        {
            debugByte = 1;
            usart_spec_write(0x33); //'3'
            delayMilli(800);
            usart_spec_write(0x34); //'4'
        } else {
            usart_spec_write(0x41); //'A'
            debugByte = 0;
        }
    }
}

 //when Timer0 counter overflows this block of code will run
 //used for delayMilli function
 void TC0_Handler(void) {
     //read status register - this clears interrupt flags
     uint32_t status = REG_TC0_SR0;

     if ((status & TC_SR_CPCS)>=1){
         cycle++;
     }
 }

I would appreciate some help to see, where I went wrong with the setup. I also hope this will be helpful for future software developers smiley

 

Regards!

Szisti01

 

 

 

This topic has a solution.
Last Edited: Mon. Aug 20, 2018 - 02:24 PM
This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

When connecting to my laptop with an RS-232 converter ...

for example my output was 0b0100_0001 (0x41, 'A') while my reading is 0b0101_1111 (0x5F, '_'). The conversion steps are for ASCII codes:

1) Bitwise inversion

2A) 1 Bitwise shift to the right if ASCII code is ODD

2B) 2 Bitwise shift to the right if ASCII code is EVEN

 It sounds to me like your "RS-232 converter" isn't doing what you need.   Since the Xplained board does not have any "real" rs232 ports, you probably need a "logic Level Serial to USB converter", and what you have is a "real" rs232 converter.  "Real rs232" is inverted with respect to the logic-level signals, and the shifting is probably explained by the receiving UART hunting for start and/or stop bits.

(It's a coincidence that simply inverting the TTL signal will give you waveforms that are "close enough to rs2323 to work with many implementations of rs232 hardware.")

 

As a rule, if you have something with a DE-9 connector, you should only plug it into a matching connector.

 

The logic level converters are common and cheap these days.  Another solution (if this is the problem) is to find a logic-to-rs232 converter to put in between the Xplained board and your cable.

 

(Your analysis and workaround is quite impressive.  Most people stop with "it's not working right!")

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thank you for the fast reply!

This seems to be a good reason, so I will just order a pair of RS232 and RS485 (this is the target communication later) transceivers, and make some tests on them next week. I will give you some updates then, and if everything is right the topic can be closed!

 

Just a side question, is it correct that I cannot use the Debug USB for serial communication (other than reprogramming and Debugging with Atmel studio)?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

No it's not correct, you can use it all you want for serial communication. It's used as a "console" in example ASF (ver 3) projects for the SAM4S Xplained Pro for example.

/Lars

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Sorry for the late reply, I am still waiting on the components.

 

Thank you Lajon for the suggestion, I found the example, and was able to set it up. However when I use both UART1 (DBG USB) and USART1 (my RS-232) then the USB can use only baudrates 19200 and below. Else I get garbage data, but the same amount of bytes, the same conversion method I used before cannot be applied there. If I set up the sysclock the default way (PLLA instead of XTAL) then it can go with any rates I tested (up to 115200), but then my other timings are off (USART1 10x faster, TC0 20x faster), so I prefer to keep the XTAL for now. Besides 19200 Baud is still good for debugging, and that is what I needed!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

So I finished the testing for both RS-232 and RS-485 communication, using specific transceivers. Both application works perfectly, which means >westfw gave the right solution!

 

In the meantime I found a strange thing, namely that changing my Baud-rate definition for the RS communications doesnt update in reality, only, if I put the number directly into the structure.

	const sam_usart_opt_t usart_rs485_settings = {
		USART_BAUDRATE,         //set to 19200, still uses 9600
		US_MR_CHRL_8_BIT,
		US_MR_PAR_NO,
		US_MR_NBSTOP_1_BIT,
		US_MR_CHMODE_NORMAL
	};
	
	//some initialization steps
	
	usart_init_rs485(RS_USART, &usart_rs485_settings, sysclk_get_peripheral_hz());

If I put USART_BAUDRATE back it will still use the previous settings. When I hover the mouse over it shows the defined value as I write it, and only shows one reference. Renaming the #define will still have the same behaviour, so I guess it is a kind of compiler bug.

 

Otherwise I found a similar topic to my initial one. His reading is converted in a same way as mine:

https://www.avrfreaks.net/forum/...

 

Thanks for all the help!