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.
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 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
Regards!
Szisti01