I've changed the code for the receiver but the transmitter is pretty much the same, so in the receiver I've canceled the Interrupt and instead I read the data in a loop where I check every time for the state of the RC2IF_bit and the check is made by the same order the transmitter sends the data to make sure which port is sending data.
The problem is in simulation on proteus when I receive the data and output it on leds they work fine and the data is sent right but in the middle of the simulation when I watch it I found that they change states for a glance, for example if i send PORTA = 0X2D I receive the same value and the right leds turn-on but for a second they turn-off then they turn-on again, is this a problem in the code written.
/*This is the transmitter code*/
void UART2_TX_init (); //UART2 transmission initialization function porototype
void SEND_data (int output); //Send data function prototype
void main()
{
ANSELA = 0X00; //Disable analogue function on PORTA
ANSELE = 0X00; //Disable analogue function on PORTE
ANSELF = 0X00; //Disable analogue function on PORTF
TRISA = 0XFF; // SET PORTA AS INPUT (AUTOMATIC BUTTONS)
TRISB = 0XFF; //SET PORTB AS INPUT (OFF BUTTONS)
TRISD = 0XFF; //SET PORTD AS INPUT (MANUAL BUTTONS)
TRISE = 0XFF; //SET PORTE AS INPUT (HIGH BUTTONS)
TRISF = 0XFF; //SET PORTF AS INPUT (LOW BUTTONS)
TRISC = 0XFF; //SET PORTC AS INPUT (TRIP BUTTONS)
TRISG0_bit = 0; //set PORTC pin0 as output for MAX487 DE pin
PORTG.F0= 1; //set PORTC pin0 HIGH , set MAX487 as transmitter.
UART2_TX_init(); //call UART1 transmission initialization
while (1)
{
SEND_data(PORTA); //send data of automatic
delay_ms(10);
SEND_data(PORTB); //send data of off
delay_ms(10);
SEND_data(PORTD); //send daata of manual
delay_ms(10);
SEND_data(PORTE); //send data of high
delay_ms(10);
SEND_data(PORTF); //send data of low
delay_ms(10);
SEND_data(PORTC); //send data of TRIP
delay_ms(10);
}
}
/*This function takes the data needed to be send
as an integer. Wait for the TSR to be empty and
start the transmission*/
void SEND_data (int output)
{
while (!TRMT_TX2STA_bit){}; //checks if TSR is empty or not if empty TRMT_BIT is set and write to transmit register
TX2REG = output; //write data to be send in the transmission register
}
/*This function initializes the UART2 as an asynchronous
transmitter at a baud rate of 9600kbps*/
void UART2_TX_init ()
{
BAUD2CON = 0X08;
BRGH_TX2STA_bit = 1;
SP2BRGL = 207;
SYNC_TX2STA_bit = 0X00;
SPEN_RC2STA_bit = 0X01;
TRISG1_bit = 0X01;
TRISG2_bit = 0X01;
TXEN_TX2STA_bit = 0X01;
}
/*This is the receiver code*/
void UART2_RX_init (); // Receiver initialization function prototype
void main()
{
ANSELA = 0X00; // Disable analog function on PORTA
ANSELE = 0X00; // Disable analog function on PORTE
ANSELF = 0X00; // Disable analog function on PORTF
TRISA = 0X00; //set PORTA as output
TRISB = 0X00; //set PORTB as output
TRISD = 0X00; //set PORTD as output
TRISE = 0X00; //set PORTE as output
TRISF = 0X00; //set PORTF as output
TRISC = 0X00; //set PORTF as output
PORTA = 0x00; //clear PORTA
PORTB = 0x00; //clear PORTB
PORTD = 0x00; //clear PORTD
PORTE = 0x00; //clear PORTE
PORTF = 0x00; //clear PORTF
PORTC = 0x00; //clear PORTC
TRISG0_bit = 0x00; //set PORTC pin0 as output for MAX487 RE pin
PORTG.F0 = 0x00; // set PORTC pin0 as LOW , set MAX487 as receiver
UART2_RX_init(); //call receiver initialization function
while (1)
{
while (!RC2IF_bit) ; //check if the RCIF flag is up to tell if there is a new data
PORTA =~ RC2REG; //write the new data to the specified port
while (!RC2IF_bit) ;
PORTB =~ RC2REG;
while (!RC2IF_bit) ;
PORTD =~ RC2REG;
while (!RC2IF_bit) ;
PORTE =~ RC2REG;
while (!RC2IF_bit) ;
PORTF =~ RC2REG;
while (!RC2IF_bit) ;
PORTC =~ RC2REG;
}
}
/*This function initializes UART2 as an asynchronous
receiver at a baud rate of 9600kbps with continous
reception NO INTERRUPT ON RECEIVE*/
void UART2_RX_init ()
{
BAUD2CON = 0X08;
BRGH_TX2STA_bit = 1;
SP2BRGL = 207;
SYNC_TX2STA_bit = 0X00;
SPEN_RC2STA_bit = 0X01;
TRISG1_bit = 0X01;
TRISG2_bit = 0X01;
CREN_RC2STA_bit = 0X01;
}
First of all I want to say a few words about protocol design. Any communication protocol, if you want it to be reliable, should implement at least two things: frame synchronization and error checking. Okay, there are some specialized protocols that don't use frames and represent data as a continuous stream, but it's definitely not your case. So if you don't want to mess around with weird bugs, I highly recommend you to implement these things.
Now about your code. It looks like GET_data waits for the transmit register to be empty and writes to it one byte. I don't see anything wrong with that. But your receiver looks suspicious. You wait for the RCIF flag to be set and then read 5 times from the input register RCREG. But non-zero RCIF means that you received one byte. You can't wait for RCIF once and then read from RCREG multiple times. You should wait for RCIF before every read from RCREG.
I would be happy to give you an example of the working code, but I can't come up with a simple solution that will fit your current architecture.
I can give you example how to do it in a right way, but it will look totally different.
Some things:
the UART receive ISR should be as short as possible and just write the data into a buffer and contain absolutly not any delay routines.
use one interupt for every received byte.
start your frame with a startbyte. e.g 'S'
end your frame with a checksum byte.
do the portwrite in your mainloop after you detect a complete frame in your buffer (startbyte + databytes + correct chechsum)
Related
I am trying to use the SPI communication to read data from the ADXL345 accelerometer. I configured the different pins and SPI in master mode, and tried reading the x, y and z axis accelerations.
My issue is that the SPI readings are always 0. I tried debugging to find the issue and I realized that RXNE is never set even though I'm transmitting data and I don't really get why.
I'm using STM32F103 Board.
Here's my code:
#include "Driver_GPIO.h"
#include "stm32f10x.h"
uint8_t RxData[6];
int x,y,z;
float x_acc,y_acc,z_acc;
void GPIO_Config (void)
{
MyGPIO_Struct_TypeDef NSS={GPIOA,4,Out_OD}; // Output Open Drain
MyGPIO_Struct_TypeDef SCK={GPIOA,5,AltOut_Ppull}; // Alternate Output Push-Pull
MyGPIO_Struct_TypeDef MISO={GPIOA,6,In_Floating}; // Input Floating
MyGPIO_Struct_TypeDef MOSI={GPIOA,7,AltOut_Ppull}; // Alternate Output Push-Pull
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN; //enable GPIOA clk
MyGPIO_Init(&NSS);
MyGPIO_Init(&SCK);
MyGPIO_Init(&MISO);
MyGPIO_Init(&MOSI);
}
void SPI_Enable (void)
{
SPI1->CR1 |= (SPI_CR1_SPE); // SPE=1, Peripheral enabled
}
void SPI_Disable (void)
{
SPI1->CR1 &= ~(SPI_CR1_SPE); // SPE=0, Peripheral Disabled
}
void CS_Enable (void)
{
GPIOA->BSRR |= GPIO_BSRR_BR9;
}
void CS_Disable (void)
{
GPIOA->BSRR |= GPIO_BSRR_BS9;
}
void SPI_Config(void){
RCC->APB2ENR |= RCC_APB2ENR_SPI1EN; // Enable SPI1 CLock
SPI1->CR1 |= SPI_CR1_CPOL| SPI_CR1_CPHA; // CPOL=1, CPHA=1
SPI1->CR1 |= SPI_CR1_MSTR; // Master Mode
SPI1->CR1 |= (SPI_CR1_BR_0)| (SPI_CR1_BR_1); // BR[2:0] = 400: fPCLK/16, PCLK2 = 72MHz, SPI clk = 3.375MHz
SPI1->CR1 &= ~SPI_CR1_LSBFIRST; // LSBFIRST = 0, MSB first
SPI1->CR1 |= (SPI_CR1_SSM) | (SPI_CR1_SSI); // SSM=1, SSI=1 -> Software Slave Management
SPI1->CR1 &= ~SPI_CR1_RXONLY; // RXONLY = 0, full-duplex
SPI1->CR1 &= ~SPI_CR1_DFF; // DFF=0, 8 bit data
SPI1->CR2 = 0;
}
void SPI_Transmission(uint8_t *data, int size){
uint8_t clear;
//check flag TxE //
int i=0;
while (i<size)
{
while (!((SPI1->SR)&(SPI_SR_TXE))){}; // buffer is empty
*(volatile uint8_t *)&SPI1->DR = data[i];
i++;
}
while (!((SPI1->SR)&(SPI_SR_TXE))){}; // buffer is empty
while (((SPI1->SR)&(SPI_SR_BSY))){}; // buffer not communicating
clear= SPI1->DR; // empty Overrun flag
clear= SPI1->SR;
}
void SPI_Receive (uint8_t *data,int size)
{
while (size)
{
while (((SPI1->SR)&(SPI_SR_BSY))) {}; // buffer not communicating
*(volatile uint8_t *)&SPI1->DR = 0; // dummy data
while (!((SPI1->SR) &(SPI_SR_RXNE))){};
// buffer is not empty
*data++= *(volatile uint8_t *)&SPI1->DR;
size--;
}
}
void adxl345_write (uint8_t address, uint8_t value)
{
uint8_t data[2];
data[0] = address|0x40; // multibyte write
data[1] = value;
CS_Enable (); // pull the cs pin low
SPI_Transmission (data,2); // write data to register
CS_Disable (); // pull the cs pin high
}
void adxl345_read (uint8_t address, uint8_t *RxData)
{
address |= 0x80; // read operation
address |= 0x40; // multibyte read
CS_Enable (); // pull the pin low
SPI_Transmission (&address,1); // send address
SPI_Receive (RxData,6); // receive 6 bytes data
CS_Disable ();; // pull the pin high
}
void adxl345_init (void)
{
adxl345_write (0x31, 0x01); // data_format range= +- 4g
adxl345_write (0x2d, 0x00); // reset all bits
adxl345_write (0x2d, 0x08); // power_cntl measure and wake up 8hz
}
int main(void)
{
GPIO_Config();
SPI_Config();
SPI_Enable();
adxl345_init();
do{
adxl345_read(0x32,RxData);
x = ((RxData[1]<<8)|RxData[0]); // DATA X0, X1
y = ((RxData[3]<<8)|RxData[2]); // DATA Y0, Y1
z = ((RxData[5]<<8)|RxData[4]); // DATA Z0, Z1
// Scale Factor for Xout, Yout and Zout is 7.8 mg/LSB for a +-4g, 10-bit resolution
// ==> multiply by 0.0078 to get real acceleration values
x_acc= x * 0.0078;
y_acc= y * 0.0078;
z_acc= z * 0.0078;
}while(1);
}
As already stated you have a lot of issues here
Why NSS pin is configured open-drain? Typically CS lines are push-pull. I don't know the schematics, but this is the first time I see an open-drain CS
In GPIO_Config NSS is pin 4, yet pin 9 is toggled from CS_Enable
If F1 series there is separate clocking bit for the alternate functions, it's not enabled
It is also weird that you are telling that RXNE is always zero and the readings returns zero. Your code should stuck in while loops if RXNE stays zero
I will not analyze magic numbers as I do not have time check every number in the RM. But you have many obvious issues.
Deley or readback is required after enabling the peripheral clock. You instantly set the registers which is wrong. Add __DSB(); or readback (for example (void)RCC->APB2ENR;). Same for all peripherals
I need to communicate with an eeprom chip(25lc1024) via SPI.
I can get the following code to work but have to resort to delays isntead of the flags alone.
Otherwise I can see on the scope that it is not waiting for all the bits to be shifted out and proceeds.
Any ideas why the flags are not stopping it?
void Init_SPI(void){
RCC->APB2ENR |= RCC_APB2ENR_SPI1EN; // enable SPI clock
GPIOA->AFR[0] |= SET_AFL_A_FOR_SPI1;
GPIOB->AFR[0] |= SET_AFL_B_FOR_SPI1;
SPI1_NSS = DESELECT_CHIP; // set the SS pin high
// initialize the SPI configuration register
SPI1->CR1 = SPI_CR1_MSTR // SPI master mode
| SPI_CR1_BR_1; // 010 bit rate prescale /8 (60MHz/8 = 7.5MHz)
SPI1->CR2 = SPI_CR2_SSOE;
SPI1->CR1 |= SPI_CR1_SPE; // enable SPI
}
unsigned int eeprom_read(unsigned long address, unsigned int chars_to_read)
{
char temp;
unsigned int result = 0;
SPI1_NSS = SELECT_CHIP; // set the SS pin low
SPI1->DR = READ_FROM_SPI; // send data out SPI
while( !(SPI1->SR & SPI_SR_TXE) ); // wait until transmit buffer empty
SPI1->DR = (address & 0xFF0000) >> ADJ16; // send data out SPI
while( !(SPI1->SR & SPI_SR_TXE) ); // wait until transmit buffer empty
SPI1->DR = (address & 0x00FF00) >> ADJ8; // send data out SPI
while( !(SPI1->SR & SPI_SR_TXE) ); // wait until transmit buffer empty
SPI1->DR = (address & 0x0000FF); // send data out SPI
while( !(SPI1->SR & SPI_SR_TXE) ); // wait until transmit buffer empty
delay();
temp = SPI1->DR;
SPI1->DR = DUMMY_8BIT; // send dummy 8 bits to generate clock
chars_to_read--;
while( !(SPI1->SR & SPI_SR_RXNE) ); // wait until receive buffer is not empty
//USART2->DR = SPI1->DR;
result = SPI1->DR;
if(chars_to_read != 0){
while((SPI1->SR & SPI_SR_RXNE) ); // wait until receive buffer is empty
delay();
SPI1->DR = DUMMY_8BIT; // send dummy 8 bits to generate clock
//delay();
while( !(SPI1->SR & SPI_SR_TXE) ); // wait until transmit buffer is empty
while( !(SPI1->SR & SPI_SR_RXNE) ); // wait until receive buffer is not empty
temp = SPI1->DR;
result = (result*256) + temp;
chars_to_read--;
}
delay();
SPI1_NSS = DESELECT_CHIP; // set the SS pin high
return result;
}
static void delay(void)
{
unsigned int j = FALSE;
for (j = 0; j < 25; j++) {
}
}
I am looking to receive serial data from an arduino, and then transmit the data received back to the arduino, however I am having trouble receiving the correct data. Below is my code, I am not sure on where I have gone wrong, can anyone see any problems?
I am using register level programming and using USART 3 on the STM32L476RG development board, an I am using ADM485 chip to transfer the data between each serial port.
#include "stm32L476XX.h"
#include "stdio.h"
int T ;
int R ;
uint8_t z;
void USART3_init(void)
{
USART3->BRR |= 26UL<<4; //BAUD RATE MANTISSA 234UL<<4
USART3->BRR |= 1UL<<0; // BAUD RATE FRACTION 6UL<<0
USART3->CR1 |= 1UL<<0; //enable USART
USART3->CR1 ^= 0UL<<28; //1 start bit, 8 data bits, n stop bit
USART3->CR1 ^= 0UL<<12; //also sets word length to 8 data bits
USART3->CR1 ^= 0UL<<10; //no parity control
USART3->CR1 |= 1UL<<6; //Transmission complete interrupt enabled
USART3->CR1 |= 1UL<<7; //TXE interrupt enable
USART3->CR1 |= 1UL<<5; //RXNEIE interrupt enable
USART3->CR2 ^=00UL<<12; //1 stop bit
USART3->CR1 |= 1UL<<3; // enable transmitter
USART3->CR1 |= 1UL<<2; // enable receiver
NVIC_EnableIRQ(USART3_IRQn); //enable USART interrupts
}
void Delay(void)
{
uint32_t i=0;
for (i=0; i<50000; i++){}
}
void USART3_IRQHandler(void)
{
//Delay();
if ((USART3->ISR>>5)&1UL) //Check if RXNE interrupt is high
{
z = USART3->RDR; //put what is on RDR into Z (also clears RXNE flag)
GPIOB->ODR |= 1UL<<5; //set transceiver into transmit mode USART3->TDR = z; // Clears TXIE flag and outputs z on TX
}
if ((USART3->ISR>>7)&1UL) //Check if TXIE interrupt is high
{
GPIOB->ODR &= 0UL<<5; //sets transceiver in receive mode
}
if ((USART3->ISR>>6)&1UL) //Check if TC interrupt is high
{
USART3->ICR |= 1UL<<6; //Clear TC flag
GPIOB->ODR &= 0UL<<5; //Set transceiver in receive mode
}
}
void RCC_GPIO_init(void)
{
RCC->APB1ENR1 |= 1UL<<18; //Enable USART 3 clock
RCC->AHB2ENR |= 1UL<<1; //Enable GPIOB clock
GPIOB->MODER = 0; //reset all register bits
GPIOB->MODER |= 2UL<<20; //enable GPIOB pin 10 as alternate function
GPIOB->MODER |= 2UL<<22; //enable GPIOB pin 11 as alternate function
GPIOB->MODER |= 1UL<<10; //enable GPIOB pin 5 as output
GPIOB->AFR[1] = 0; //reset all register bits
GPIOB->AFR[1] |= 7UL<<8; //enable GPIOB pin 10 as TX
GPIOB->AFR[1] |= 7UL<<12; //enable GPIOB pin 10 as RX
GPIOB->ODR ^= 0UL<<5; //GPIOB pin 5 as low (to put ADM485 transceiver in receive mode)
}
int main (void)
{
RCC_GPIO_init();
USART3_init();
while(1)
{
}
}
I am attempting to program two MSP430s to essentially instant message through PuTTY, but cannot figure out how to get typed information onto the MSP430 without the debugger. I'm using CCS and it's an MSP430 F2274. I have one program in which the user inputs in morse code on the button on one MSP430 that successfully outputs to PuTTY off another MSP430 via the following method.
void displayString(char array[], char size) {
WDTCTL = WDTPW + WDTHOLD; // Disable WDT
DCOCTL = CALDCO_8MHZ; // Load 8MHz constants
BCSCTL1 = CALBC1_8MHZ; //
P3SEL |= 0x30; // P3.4,5 = USCI_A0 TXD/RXD
UCA0CTL1 |= UCSSEL_2; // SMCLK
UCA0BR0 = 0x41; // 8MHz 9600
UCA0BR1 = 0x03; // 8MHz 9600
UCA0MCTL = UCBRS1; // Modulation UCBRSx = 2
UCA0CTL1 &= ~UCSWRST; // **Initialize USCI state
int count;
for(count=0; count<size; count++){
while (!(IFG2&UCA0TXIFG)); // USCI_A0 TX buffer ready?
UCA0TXBUF = array[count]; // TX -> RXed character
}
}
Can someone send code that does the reverse (types information onto MSP430) with a similar setup? thanks.
I used picocom:
$ picocom -r -b 9600 /dev/ttySxxxx
Code for UART initialization:
void uart_setup()
{
// Configure UART pins
P2SEL1 |= BIT0 + BIT1;
P2SEL0 &= ~(BIT0 + BIT1);
// Configure UART 0
UCA0CTL1 |= UCSWRST; // perform reset
UCA0CTL1 = UCSSEL_1; // Set ACLK = 32768 as UCBRCLK
UCA0BR0 = 3; // 9600 baud
UCA0BR1 = 0;
UCA0MCTLW |= 0x5300; // 32768/9600 - INT(32768/9600)=0.41
// UCBRSx value = 0x53 (See UG)
UCA0CTL1 &= ~UCSWRST; // release from reset
//UCA0IE |= UCRXIE; // Enable RX interrupt
}
Override putchar():
int putchar(int c)
{
if (c == '\n') putchar('\r');
while (!(UCA0IFG & UCTXIFG));
UCA0TXBUF = c;
return 0;
}
And then you can simple call printf(...) to output text from the MSP430 to the serial port.
If you still want to leave putchar() and prtinf() for debug purpose - printing into debug window of debugger, then you can have separate read function:
unsigned char ReadByteUCA_UART(void)
{
//while ((IFG2&UCA0RXIFG)==0); // wait for RX buffer (full)
while(UCA0STAT&UCBUSY);
return (UCA0RXBUF);
}
I am using the UART of Atmega169/AVR Butterfly for transmission to another board, baudrate 56700, no parity, 1 stopbit, no flow control. The oscillator is running at 7,3768Mhz (checked). I can transmit data successfully (checked with the other board and PC/HyperTerminal), but not receive any data - when running the debugger the configuration bits are all set correctly, but RXC is false constantly - I also checked if I can send data to myself (connected TXD to RXD and grounded), but without success. (Tried with ISR as well as polling)
Below are the relevant parts of the code, I hope you can deal with it - PORTB is used as output for testing with the oscilloscope (I know I could just use one pin, but there is nothing else on PORTB right now):
int main(void){
OSCCAL_Calibrate(); // calibrate the internal oscillator
int UBRR_VAL = ((F_CPU)/(BAUD*16)-1);
UART_Init(UBRR_VAL);
DDRB |= 0xFF;
PORTB = 0;
testCharSend();
while(1);
return 0;
}
void testCharSend()
{
char i = 'x';
while(1){
Uart_Tx(i);
}
}
void UART_Init(unsigned int baudrate)
{
// Set baud rate
UBRRH = (unsigned char)(baudrate>>8);
UBRRL = (unsigned char)baudrate;
UCSRA = 0;
// Enable receiver and transmitter
UCSRB = (1<<RXEN)|(1<<TXEN);
// Async. mode, 8bit, No parity, 1 stop bit (like CC2540)
UCSRC = (0<<UMSEL)|(0<<UPM0)|(0<<USBS)|(3<<UCSZ0)|(0<<UCPOL);
// enable receive interrupt
UCSRB |= (1<<RXCIE);
// flush UART
UART_Flush();
}
void UART_Flush( void )
{
unsigned char dummy;
while ( UCSRA & (1<<RXC) ) dummy = UDR;
}
void Uart_Tx(char data)
{
while (!(UCSRA & (1<<UDRE)));
UDR = data;
}
ISR (USART0_RX_vect)
{
PORTB ^= 0xFF;
char c = UDR;
}
OK, I tested the connections with an oscilloscope, the RXD line on the board was broken, switched the board and now it's working, so the code above is valid!