This thread has been locked.
If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.
hi,
How to send and receive multiple bytes in 1 shot?
Now I'm using UCA0RX to receive 1 byte and send out through UCA1TX. I want to make it 4 byte, how to do that?
Is there any macro to do that?
Thanks
Regards,
Ong
The USCI module buffers are only a single byte, so you will have to write a driver that handles the transmission of multiple bytes.
In its simplest form of UART (using active state wait), something like this should work to transmit data
unsigned char uartSend(unsigned char *pucData, unsigned char ucLength) { while(ucLength--) { // Wait for TX buffer to be ready for new data while(!(UCA1IFG & UCTXIFG)); // Push data to TX buffer UCA1TXBUF = *pucData; // Update variables ucLength--; pucData++; } // Wait until the last byte is completely sent while(UCA1STAT & UCBUSY); }
Edit: Fixed typo in the above function
On the receiving side (using active state wait), one should wait until the UCRXIFG flag is set, then read the content of the of the RX buffer.
Note that it is a much better method to use interrupt driven UART/SPI.
There are several examples in the MSP430ware found at http://www.ti.com/tool/msp430ware
Hope this helps!
Br,
ABO
--
PS. Thank you for clicking Verify Answer below if this answered your question!
Hi,
If I want to send 2 bytes of data like 0x21 and 0x38, I have to write uartSend(0x2138,2); ?
Thanks
Chu En Ong said:If I want to send 2 bytes of data like 0x21 and 0x38, I have to write uartSend(0x2138,2); ?
No.
In 'C' programming, the parameters that you pass when you call a function must match what the function is expecting - as shown in its prototype and/or definition.
Look at the prototype of TIABO's suggested uartSend() function:
TIABO said:unsigned char uartSend( unsigned char *pucData, unsigned char ucLength );
What do you notice about the first parameter...?
Oops - typo:
TIABO said:unsigned char uartSend( unsigned char *pucData, unsigned char ucLength ) { while(ucLength--) { // Wait for TX buffer to be ready for new data while(!(UCA1IFG & UCTXIFG)); // Push data to TX buffer UCA1TXBUF = pucData; // pucData is a pointer!
Maybe that confused the OP?
If I want to pass the value in hexadecimal instead of ASCII number? How to do that?
Thanks
As suggested, I do believe my suggested function contains a typo:
unsigned char uartSend( unsigned char *pucData, unsigned char ucLength )
{
while(ucLength--)
{
// Wait for TX buffer to be ready for new data
while(!(UCA1IFG & UCTXIFG));
// Push data to TX buffer
UCA1TXBUF = *pucData; // Assigning the value pointed to by pucData to register UCA1TXBUF
}
}
Chu En Ong said:I want to pass the value in hexadecimal instead of ASCII number? How to do that?
If you want to send two bytes using the above function, you should do something like this:
unsigned char dataArray[2] = {0x42, 0x43}; // Variable dataArray is now an unsigned char pointer (the type accepted by the function) uartSend(dataArray, 2);
If you want to send a signle byte, stored in a variable of type unsigned char, you do something like this:
unsigned char data = 0x42; uartSend(&data, 1); // The & in front of data means we're passing the address (i.e. pointer) of the data variable to the function.
Br,
ABO
Thanks for your help. Do you know how to receive 2 bytes of data from PC?
The idea is receive data from PC through UCA0 and send out from MSP through UCA1.
Now what I can do is receive 1 byte and send 2 bytes out. How to change it to receive 2 bytes?
Here is my code.
#include "msp430x54x.h"
unsigned char counter;
unsigned int i = 0;
unsigned char data[2]= {0x41,0x41};
unsigned char data1[2]= {0x41,0x42};
unsigned char uartSend(unsigned char *pucData, unsigned char ucLength)
{
while(ucLength)
{
// Wait for TX buffer to be ready for new data
while(!(UCA1IFG & UCTXIFG));
// Push data to TX buffer
UCA1TXBUF = *pucData;
// Update variables
ucLength--;
pucData++;
}
// Wait until the last byte is completely sent
while(UCA1STAT & UCBUSY);
}
void main(void)
{
WDTCTL = WDTPW + WDTHOLD; // Stop WDT
P3SEL = 0x20;
P5SEL = 0x40; // P3.4,5 = USCI_A0 TXD/RXD
P5DIR = 0xFF;
P10SEL = 0x00; // P3.4,5 = USCI_A0 TXD/RXD
P10DIR = 0xFF;
P3DIR = 0xFF;
UCA0CTL1 |= UCSWRST; // **Put state machine in reset**
UCA0CTL1 |= UCSSEL_2; // SMCLK
UCA0BR0 = 6; // 1MHz 9600 (see User's Guide)
UCA0BR1 = 0; // 1MHz 9600
UCA0MCTL = UCBRS_0 + UCBRF_13 + UCOS16; // Modln UCBRSx=0, UCBRFx=0,
// over sampling
UCA1CTL1 |= UCSWRST; // **Put state machine in reset**
UCA1CTL1 |= UCSSEL_2; // SMCLK
UCA1BR0 = 6; // 1MHz 9600 (see User's Guide)
UCA1BR1 = 0; // 1MHz 9600
UCA1MCTL = UCBRS_0 + UCBRF_13 + UCOS16; // Modln UCBRSx=0, UCBRFx=0,
UCA0CTL1 &= ~UCSWRST; // over sampling
UCA1CTL1 &= ~UCSWRST; // **Initialize USCI state machine**
UCA0IE |= UCRXIE; // Enable USCI_A0 RX interrupt
__bis_SR_register(LPM0_bits + GIE); // Enter LPM0, interrupts enabled
//__no_operation(); // For debugger
}
// Echo back RXed character, confirm TX buffer is ready first
#pragma vector=USCI_A0_VECTOR
__interrupt void USCI_A0_ISR(void)
{
counter = UCA0RXBUF;
if(counter == 0x00)
{
uartSend(data ,2);
P5OUT = 0x00;
P3OUT = 0x00;
P10OUT = 0x00;
}
else if(counter == 0x01)
{
uartSend(data1 ,2);
P10OUT = 0x00;
P5OUT = 0x00;
P3OUT = 0x01;
}
else if(counter == 0x02)
{
UCA1TXBUF = 0xFF;
P10OUT = 0x00;
P5OUT = 0x00;
P3OUT = 0x02;
}
}
Bytes are received one at the time. When a byte has been received in the UART RX FIFO, the UCAxIFG.UCRXIFG flag is set to 1.
The MSP430 UART RX fifo is 1 byte. The best way is to use interrupts (triggering on UART RX "byte received") to copy the received byte to an internal buffer. Depending on your application, you can (a) configure a DMA channel to copy the received bytes for you (leaving more time for the CPU to do other things), or you can (b) use the CPU to copy the byte in an interrupt service routine (ISR).
The simplest way, but the slowest, is to poll the UCAxIFG.UCRXIFG flag. So, to read two bytes, the sequence could be something like this:
if(UCRXIFG is set) { // Clear the UCRXIFG flag // copy byte from RX FIFO to internal buffer }
Hope this helps.
Br,
ABO
dear;
I have a project, due date in 10days, developing blinking cursor, help commands and pipe line all to be from shell(from CLI to control the msp430). my launchpad is g2553 series. I am newbie. any help please, especially i have no idea on the pipeline.
thanks!
Tight. Whoever gave you the project seems to think that it can be done. So either he also have the required background information or he's totally underestimating the task.Garoma G. Gonfa said:I have a project, due date in 10days, [] I am newbie.
There should be a G2553 USCI UART demo available. However, it does only echoing incoming data. it does not handle receiving or sending a data string.
Blinking a cursor requires use of a timer to cyclic send an underline, backspace, underline etc.
Well, building the pipeline and doing the help command is plain C and not MSP specific. The difficult part (because it deals with MSP interrupts and hardware) is stuffing the pipeline with incoming data and sending data that has been stuffed into the pipeline by the main code.
However, this forum is full of threads dealing with UART I/O, implementation of a ringbuffer for background UART transfers etc. An dwith comments about the demo code available.
Well, there are many different implementations possible.Garoma G. Gonfa said:especially i have no idea on the pipeline
Anotehr possible implementaiton is a variable length buffer (complete decouplign of sender and receiver). Which can take large amounts of ram.
Given teh low ram available on the 2553, I'd suggest going for the first solution. It's not really a pipeline as it blocks until everything is sent, but it is easiest to implement (you don't even need a TX interrupt handler). But definition of a pipeline is rather vague.
thanks for your suggestions; I think the professor just wanted me to bring something done hard for his own ongoing project. Yea I also don't feel comfortable with the short time period: 10days.
anyways I will search the threads here to get the ideas you indicated.
BTW, the help is not only help, after somebody write help LED for instance the options come up should show number of LEDS, what the user can do, ON/OFF/TOGGLE and when the user entered one of them on the CLI, he/she should be able to put ON/OFF/Toggle the leds.
the same is true for the ADC, and Button.
I would be happy if i can get some code snippets in meantime, because I hope you guys have already done this stuffs while I am struggling to capture every thing in this short time while following the other courses also.
heartfelt thanks!
Hi,
I am now using MSP430F240 connecting with a wireless chip called ANT. I can send message out, while when I am trying to receive the data sent to MSP430. There is overflow and cause a framing error for the UART. I guess it may be related with the baud rate. I have several questions. Firstly, when UART is sending multiple datas out, does it automatically add some delay between different datas, or the delay between different datas are caused because the Tx buffer need some time to be ready for the next byte after it send out one byte?
Second, If there is overflow for the RxBuf, which means the next byte comes before I read the first byte out from the Rx Buffer. What does it mean by reading a byte from the RxBuffer? Do I have to use a interrupt to read things from UART Rx Buffer out?
Thanks very much.
SiLi
hey all;
I am doing a simple shell for msp430g2553. I want to on/off/toggle the leds from CLI. I have managed to send the action commands(led1 on/off/toggle), but i face a problem with the toggle.
I have set some toggling delay but i couldn't make my shell go out of it.
that is for instance:
msp430>led1 on //puts the red led on on the board
msp430> //i get prompt from my shell for any of my next command i want to enter
but when i do the following:
msp430>led1 toggle //it toggles the led but couldn't go to the next execution after; how can i get out of this while the led is still toggling as my other commands
i used for loop for the toggle code, but i need to limit by some control condition the execution of the program to go to the others once the toggle command is sent.
my snippet is sth like:
if(strcmp(buffer,"led1 toggle")==0)
{
for(;;)
{
P1OUT ^= BIT0;
for(i=0;i<20000;i++); //delay between the toggle
}
writeString('\n\r'); //i do have this function but i couldn't reach this point; it says unreachable, i understand the first for loop run to infinity but i want to give toggle command once so that the led can keep toggling and give other commands for the shell to change any instruction..i know it is somewhat conflicting.
}
any help is really appreciated!
many thanks!
If your "toggle" command should make the LED toggle continuously, you should probably set up a timer that repeatedly generates interrupts. The interrupt service routine then should toggle the LED(s) that are to be toggled. This way you will get LEDs toggling in a timely fashion, and your CPU can handle the incoming commands.
Alternatively, you can alter the interpretation of the toggle command - that is that it merely toggles the state of the LED (if LED 1 was off, "led1 toggle" would turn it off, if LED1 was on, "led1 toggle" would turn it on).
Hope this helps!
Br,
ABO
i only need the first idea because i can do the second with <led on> command
if you know some basic codes about how to generate the interrupt and implement it with command please;
i normally have many other commands such as help, ADC, Button, alias.Pipeline I just want to implement them with if---else statements (to check the received commands) and implement their respective action in their separate function to be called.
But this on/off/toggle is simple and short (i thought) and want to implement them in the if--else statement itself as i depicted in the first post.
so would you please elaborate how to use the timer to implement the toggle command as your suggestion; i do have only three days lef
I suggest you look at the examples in the MSP430Ware, more specifically the timer example there (the up mode example toggles a pin on every timeout => LED). The example should get you going. http://www.ti.com/tool/msp430ware
Here's some pseudo code on how you can do it (quick draft, probably some issues in it, but it should give you the general idea):
uint8 ledsToggling = 0; #pragma vector=TIMER1_VECTOR __interupt void timerISR(void) { // Toggle LEDs given by ledsToggling variable LED_PORT ^= ledsToggling; } int main(void) { // Setup UART uartInit(); ... // Infinite loop while(1) { // Retrieve command command = uartReceive(); // Process command if(command == "led1 toggle") { // Add led1 ledsToggling |= LED1_BITMASK; // configure timer to e.g. up mode // Start timer } else if(command == "led1 on") { // Remove LED1 from toggling leds ledsToggling &= ~LED1_BITMASK; if(ledsToggling == 0) { // Stop timer if no other leds are toggling timerStop(); } // Turn led 1 on LED_PORT |= LED1_BITMASK; } ... } } Br,
ABO
Hi, in the exmple code, you should easily fnd a simple Tx interrupt. To trigger the interrupt, just make sure that you have enable GIE and TxIE. Then whenever your Txbuf is empty and ready to send another byte out, it would trigger the interrupt. So you can put your code for toggling inside the interrupt. It should work. Hope this helps.
it works ABO;
thank u!
I also put CCTL0=CCIE;
TACTL=TASSEL_2+MC_2
and
CCTLO = ~CCIE;
TACTL = TASSEL_2+mc_2;
in starts timer() and timerstop() i asked above.
Now what I left with is giving the command >led1 led2 toggle which should able to toggle both leds alternatively/or at the same time.
i have done it with a function call like this:
void LED1_LED2_TOGGLE()
{
while(1)
{
P1OUT ^= BIT0;
Delay_ms(500);
P1OUT ^= BIT6;
}
}
.....but the problem is the execution stays there forever due to the while loop which i need to break when i enter some other command.
many thanks!
Hi,
I donot know whether the question you posted just now is to reply to me, or someone else. So I just provide my opinion here. Whenever you want to stop the function in the interrupt, just Disable the TxIE outside. Or a more clever idea I think is that, put a case sentence inside your interrupt.
Switch(i)
case 1: LED1_LED2_TOGGLE();
break;
case 2: DisableTxIE();
break;
default: break;
Then make i to 1 at the beginning of your program. Wheneve you want to stop that function, just change i to 2 in the main program. Then do the things you want. After that change i back to 1 when you need.Hope it helps.
si li1,
Yes, this thread has wandered somewhat off from the initial topic, but I'm currently unable to split it into two threads.
I was trying to help Gada G. with his problem.
Gada:
The idea is that you
The point with the "ledsToggling" variable was that you could have multiple LEDs toggling at the same time. As si li1 suggested, you can have a switch case in your interrupt service routine. By using a timer to set the toggling intervals, you do not need an infinite while loop in main context.
You should try to play around with this. And again, the MSP430Ware examples will, I think, help you out a lot.
Br,
ABO
Thank you guys, your ideas made me fix the issues i raised.
It is a school project to be delivered next Monday(a kind of tight time limit with classes) and I am a bit new to it.
Now I am trying to display the content of ADC10MEM (strings of 0's and 1's) to my terminal after the ADC finish the conversion.
The idea is the user is prompted to choose the channel [ i am a little confused with what channel is] and then supposed to see the binary string on the terminal back.
i have normally two functions writechar(ch) and writestring(*str) which can display string of characters.
I would be happy if you say me something on how to get the contents of ADC10MEM register and send it to the terminal as strings of 1's and o's.
thanks a lot!
Again, see the MSP430Ware examples (e.g. adc).
Converting a hexadecimal value into strings is a good exercise. (tips: bitshift hex value and put '1' or '0' based on least significant bit).
Br,
ABO
yea, i have seen all the sample examples on slac485a about ADC i downloaded with CCS v5.2, but i couldn't see something about conversion or display. For me it is okay if i can display on my terminal hexadecimal or binary.
this may be my last request please.
thanks!
So you've figured out the ADC, thats great.
To covert a hexadecimal value into a string of 1s and 0s, something like this would work (Printing most significant bit first).
unsigned char adcValue = adcRead();
unsigned char i, tmp;
// Signal that number to come is binary by prepending a 'b'
uartPut("b", 1);
for(i=0; i<8; i++) {
// Bitshift left i times and look only at most significant bit tmp = (adcValue << i) & 0x80;
if(tmp == 0) {
uartPut('0', 1);
} else {
uartPut('1', 1);
}
}
// Write a new line character
uartPut('\n', 1);
I'm having major trouble with the text editor today, so bear with me on the formatting.
Hope this helps!
Br,
ABO
thank you ABO;
I have run the ADC examples successfully, changed the parameters and played with it; it was okay and I think I have understood how the ADC normally works.
But my project is a bit different and it is:
1.a user is asked to select the input channel from CLI[1,2,3,4,5,6,7,8,9,10]
2.the program do a single conversion for that specific channel.
3. the program send back to the terminal the binary or hexadecimal result of the conversion as string.
your pseudo code above is really helping thanks a lot.
hi;
Now i am trying to enable/disable the button on(p1.3) from CLI(my shell).
Is there a way to change the states from low to high or vice versa by command? any hint please.
thanks!
If you want to disable the button, make the microcontroller ignore the signal toggling on P1.3.Gada G. said:Now i am trying to enable/disable the button on(p1.3) from CLI(my shell).
The answer is yes (you can configure the state of GPIOs using Px, PxSEL, PxDIR registers), but what does this have to do with enabling/disabling the button?Gada G. said:Is there a way to change the states from low to high or vice versa by command? any hint please.
Br,
ABO
Hello all,
I am trying to receive binary format file(.der ), file size: 693bytes from PC to board using MSP430UART using .And send back file again from board. I have referred the answers here and also I have gone through example codes.
My implementation is as follows,
1. I used separate program for serialport communication, that will send file to board.
2. below code for the board should receive the file and transmit back the file contents to PC.
3. Using program for serialport communication, I can see the bytes received from the board to PC.
I checked various ways for my work on the below code. Still need about whether there is mistake in code. May i know about whether this code work for receiving 693 bytes binary file type?
Also while receiving file byte by byte, i need to specify the stop byte in the code. After that file will be transmit back to PC. Any body please help me how can i specify stop bit for binary formatted file.
This is my code,
//Send a log message to to the serial terminal
unsigned char uartSend(unsigned char *data)
{
ot_uint i=0;
ot_uint len = strlen(data);
while(len--){
// wait for TXBUF to complete last send...
// UCA0TXIFG is high when UCA0TXBUF is empty
while (!(UCA0IFG&UCTXIFG));
{
tx[i]=*data;
UCA0TXBUF = tx[i];
data++;
i++;
}
}
}
// Echo back RXed character, confirm TX buffer is ready first
#pragma vector=USCI_A0_VECTOR
__interrupt void USCI_A0_ISR(void)
{
int i;
switch(__even_in_range(UCA0IV,4))
{
case 0:
break; // Vector 0 - no interrupt
case 2: // Vector 2 - RXIFG
i=0;
while (!(UCA0IFG&UCTXIFG)); // USCI_A0 TX buffer ready?
{
rx[i]=UCA0RXBUF;
UCA0TXBUF = rx[i];
i++;
UCA0RXBUF++;
}// TX -> RXed character
uartSend(rx);
break;
case 4:break; // Vector 4 - TXIFG
default: break;
}
}
on overall,
1. I am trying to echo the data received to board from PC back to PC.
2. question about stop byte is, to check whether the content transmitted back to the PC correctly ,with out any additional special characters . I will also check the file size in my other program that that contains system calls open, read, write for serial communication for sending file from PC and receive file back to PC,
Hi,
Can you clarify:
Br,
ABO
Hi ,
thank for your prompt reply.
file that need be send to board is in my linux virtual machine. So i used separate program that implements open,write, read calls. for sending file, to the RX , TX Code for board in Windows 7. .
these are the answers to your questions.
1. yes i am trying to echo the data received to board from PC back to PC.
2. question about stop byte is, to check whether the content transmitted back to the PC( linux virtual machine) correctly ,with out any additional special characters . I will also check the file size in my other program that that contains system calls open, read, write for serial communication for sending file from PC and receive file back to PC,
thank you
aparna vegendla said:1. yes i am trying to echo the data received to board from PC back to PC.
The implementation depends somewhat on whether you have a multibyte RX/TX FIFO. I'm no MSP430 expert, but I do not think that is the case?
2. Send the entire file, store the received data in another and compare the two on your PC. Would that work?
Br,
ABO
thank you for your clear explanation. Now i got confirmation that ISR code work well.
While writing the program for serial port communication, I had implemented in the way that i can see the sending file and received file at linux terminal. After file back to PC, program not terminating at the linux terminal. Code for the serial port communication is implemented correctly with return statement in the main function. That is the reason why I have asked for stop bit that makes exit of program.
If you think exit of the program will depends on serial port communication program and there would be no problem to receive back file using the code that i have posted here, i will go through the other problem.
thanks for replies.
1) You should make sure your ISR is not doing too much. It is e.g. not recommended to have a while() in ISRs, in case of an error, the device will lock up (eternal while loop) in the ISR.
2) Your PC knows how many bytes it is sending, right? Exit the program when you have received as many bytes as you have sent. Not sure I understand your problem.
Br,
ABO
1) thank you. I have removed while(len--) from the ISR code, now output is being displayed with out disturbing code.
2) yes my PC knows how many bytes it is sending. As you mentioned for exiting program, i tried to modify ISR with exit(1), that terminates program after transmitting back received 693 bytes from rx. That didn't work. My project consists of lot's of functions that output code using uart. That might causing the problem of not exiting the program. I will look into the problem.
thank you
This step can be omitted if the MSP is not sending anything on its own but only echoing. Also, any kind of busy-wainting inside an ISR is a death sin anyway.TIABO said:Wait until TX buffer can accept new byte (not necessarily the same as 'byte has been transmitted')
If of course the echo of incoming bytes cna be interleaved with data the MSP sends on its own, then a synchronization is required. However, in this case, the current ISR would cause receive overflows anyway. RX and TX msut be decoupled with separate buffers then.
Hi TI Guys
I want to send multiple bytes from the MSP430g2553 to BN055 IMU, so I use the below uartSend function…would you please check it?
Also I would like to do pooling for the incoming bytes which are multiple. The BNO55 responds automatically when sending to it. Could you please help me with this? hence I do not want to use interrupts.
/////////////////////////UART send multiple Bytes//////////////////// void uartSend(unsigned char *pucData, unsigned char ucLength) { while(ucLength) { // Wait for TX buffer to be ready for new data while(!(IFG2 & UCA0TXIFG));//check if not set //if set, TX interrupt is pending // Push data to TX buffer UCA0TXBUF = *pucData; // Update variables ucLength–; //– length of data left pucData++; //shift pointer } // Wait until the last byte is completely sent while(UCA0STAT & UCBUSY); //UCBUSY indicates if USCI transmitting or receiving } unsigned char setconfigmode[5]={0xAA, 0x00, 0x3D, 0x01, 0x00}; uartSend(setconfigmode,5); delay_ms(20); // delay_ms(20)
Hello Jens-Michael,
Currently I am using interrupts but my program is stuck when enters one of the LPMs. You saw my code before, but here it is:
/* * Acceleration.c * * Created on: Oct 6, 2016 * Author: Murtadha */ #include "Acceleration.h" // the saved value of the previous measurement uint8_t cached_accelerationXMSB = 0, cached_accelerationXLSB = 0; uint8_t cached_accelerationYMSB = 0, cached_accelerationYLSB = 0; uint8_t cached_accelerationZMSB = 0, cached_accelerationZLSB = 0; uint8_t* acceleration_location; // pointer to the location used in the transmit buffer for accelerometer data typedef struct uart // UART { char *bufTXpnt; // UART TX buffer pointer unsigned int TXbuflen; // the lenght of TX block char *bufRXpnt; // UART RX buffer pointer unsigned int RXbuflen; // the lenght of RX block char RXbuffer[8]; } uartstruct; ///// macro to get string and string len #define TXSTRING(pnt) (TXdata((pnt), sizeof(pnt)-1)) uartstruct uart; // declare a struct from typedef uartstruct void TXdata( char* pnt, unsigned int len){ uart.bufTXpnt = pnt; uart.TXbuflen = len; uart.bufRXpnt = uart.RXbuffer; // reset it to beginning of ram buffer IE2 |= UCA0TXIE + UCA0RXIE; // enable USCI_A0 TX & RX interrupt } ///Intilizing the UART//////////////////////////////////////////////////// void uart_init(void){ IE2 &= ~(UCA0TXIE | UCA0RXIE); // Disable all USCIx0 (A) TX & RX interrupts UCA0CTL1 = UCSWRST; // Set UCSWRST (hold USCI in Reset state) UCA0CTL1 |= UCSSEL_2; // CLK = SMCLK // ------------ Configuring the UART(USCI_A0) ----------------// // 115200 BAUD, CLK=12MHz UCA0BR0 = 6; UCA0BR1 = 0; // //*ours: UCBRF = 8, UCBRS = 0, UCOS16 = 1 // // BITS| 7 6 5 4 | 3 2 1 | 0 | // UCAxMCTL = | UCBRFx | UCBRSx | UCOS16 | UCA0MCTL = 0x81; //this works fine UCA0CTL1 &= ~UCSWRST; // Clear UCSWRST to enable USCI_A0-UART UCA0CTL1 &= ~UCSYNC; IFG2 |= UCA0TXIFG; // preset IFG flag always left on // IE2|=UCA0RXIE; } //********************************************** //Configure clocks and clock sources void set_UCS() { /* DCO Frequency selected */ /* SCLK=SMCLK P1.5 */ /* Maximum SPI frequency for burst mode is 6.5 MHz */ //Set DCO to 12 MHz calibrated and use DCO/2 for SMCLK //Note that this is technically a bit too high for operation at 2.2Volts (end of battery life). 8 MHz is maximum recommended. //Does not seem to be a problem at room temperature. DCOCTL = CALDCO_12MHZ; //0x7A 01111010 //DCOx 011 //MODx 11010 /* External Crystal OFF, LFEXT1 is low frequency, ACLK is Divided by 1, RSELx=1110 */ // Set range 0x8E 10001110 BCSCTL1 = CALBC1_12MHZ; // DCO -> SMCLK (Default), SMCLK / 2; DCO -> MCLK, MCLK / 2; DCOR Internal Resistor select BCSCTL2 = DIVS_1 + DIVM_1 + SELM_0; // 0x52 = 00010010 /* 0.4 to 1MHz crystal , Using VLO for ACLK, Cap selected 1pF */ BCSCTL3 = LFXT1S_2; IE1 &= 0xFD; /* Disable UCS interrupt */ return; } //******************************************************************** //------------------- Configure the UART Clock source -------------------// void set_UARTUCS() { WDTCTL = WDTPW + WDTHOLD; // Stop the Watch dog DCOCTL = 0; // Select lowest DCOx and MODx settings BCSCTL1 = CALBC1_12MHZ; // Set range DCOCTL = CALDCO_12MHZ; // Set DCO step + modulation // DCO -> SMCLK (Default) IE1 &= 0xFD; /* Disable UCS interrupt */ return; } //--------- Setting the UART function for P1.1 & P1.2 --------// void setUARTPins() { // P2DIR = 0xFF; // All P2.x outputs< //P2OUT &= 0x00; // All P2.x reset P1SEL |= RXD + TXD ; // P1.1 = RXD, P1.2=TXD P1SEL2 |= RXD + TXD ; // P1.1 = RXD, P1.2=TXD // P1OUT &= 0x00; return; } //¦----------------------------- Delay Function ---------------------------------------¦ // This function will give us 1ms wait time, so for getting 10 ms, // then delay_ms(10) will give 10ms and delay_ms(100) will give 100ms void delay_ms(unsigned int ms) { unsigned int i; for (i = 0; i<= ms; i++) __delay_cycles(6000); // 6000 will give us 1ms } //¦----------------------------- US0TX ISR ---------------------------------------¦ #pragma vector=USCIAB0TX_VECTOR __interrupt void USCIAB0TX(void) // Shared A0/B0 TX IRQ vector { if (IFG2 & UCA0TXIFG){ // check for UART TX if (uart.TXbuflen){ // if not zero UCA0TXBUF = *uart.bufTXpnt++; --uart.TXbuflen; } else IE2 &= ~UCA0TXIE; // suspend IE if zero } else IFG2 = ~UCA0TXIFG; // clear a false UCB0 trigger } //¦----------------------------- US0RX ISR ---------------------------------------¦ #pragma vector=USCIAB0RX_VECTOR __interrupt void USCIAB0RX(void) // A0/B0 RX IRQ vector { if (IFG2 & UCA0RXIFG){ // check for UART RX *uart.bufRXpnt++ = UCA0RXBUF; // copy data byte // if (uart.bufRXpnt == (uart.RXbuffer[1])-'0') // { // __bic_SR_register_on_exit(LPM3_bits); // } } else IFG2 = ~UCA0RXIFG; } ///////////////getAcceleration will make the MSP430 talks to the BNO055 void getAcceleration() { // Enable intterupts //////commented on 10/12/2016 //intterupts enabled in the main function below __enable_interrupt(); // IE2 |= UCA0TXIE; // Enable the Transmit interrupt // IE2 |= UCA0RXIE; // Enable the Receive interrupt // _BIS_SR(GIE); // Enable the global interrupt //Put BNO055 in CONFIG mode********required (do not change) TXSTRING("\xAA\x00\x3D\x01\x00"); // Send this to the BNO055 to set up the CONFIG mode delay_ms(20); // do not change (80) while (IE2 & UCA0TXIE); //Put BNO055 in NORMAL power mode********required (do not change) TXSTRING("\xAA\x00\x3E\x01\x00"); // NORMAL power mode delay_ms(20); // do not change (20) delay_ms(2000) while (IE2 & UCA0TXIE); //Put BNO055 in AMG mode********selecting operating mode is required (do not change) TXSTRING("\xAA\x00\x3D\x01\x07"); // Send this to the BNO055 to set up the ACC ONLY mode delay_ms(80); // do not change (80) delay_ms(2000) while (IE2 & UCA0TXIE); TXSTRING("\xAA\x01\x08\x06"); delay_ms(10); //this delay is required..do not change (10) // delay_ms(10000) while (IE2 & UCA0TXIE); /* * ACC_DATA_X_LSB 0x08=RXbuffer[2]; * ACC_DATA_X_MSB 0x09=RXbuffer[3]; * ACC_DATA_Y_LSB 0x0A=RXbuffer[4]; * ACC_DATA_Y_MSB 0x0B=RXbuffer[5]; * ACC_DATA_Z_LSB 0x0C=RXbuffer[6]; * ACC_DATA_Z_MSB 0x0D=RXbuffer[7]; */ cached_accelerationXLSB = uart.RXbuffer[2]; cached_accelerationXMSB = uart.RXbuffer[3]; cached_accelerationYLSB = uart.RXbuffer[4]; cached_accelerationYMSB = uart.RXbuffer[5]; cached_accelerationZLSB = uart.RXbuffer[6]; cached_accelerationZMSB = uart.RXbuffer[7]; // Send this to the BNO055 to set up the CONFIG mode....DO NOT CHANGE or DELETE // TXSTRING("\xAA\x00\x3D\x01\x00"); // Send this to the BNO055 to set up the CONFIG mode // delay_ms(10); // do not change (80) delay_ms(2000) // while (IE2 & UCA0TXIE); // // // Send this to the BNO055 to set up the SUSPEND mode.... // TXSTRING("\xAA\x00\x3E\x01\x02"); // SUSPEND power mode // delay_ms(20); // do not change (20) delay_ms(2000) // while (IE2 & UCA0TXIE); ///////commented on 10/12/2016 // __bis_SR_register(LPM3_bits + GIE); // Enter LPM3 w/ int until Byte RXed return; } //¦----------------------------- Main Function-------------------------------------------¦ void doAccelerationSense() { // void doAccelerationSense(bool update) { // If called with update=true, perform a measurement //if (update) { cached_accelerationXMSB = 0; // Considered an "invalid" value cached_accelerationXLSB = 0; // means the sensor did not work cached_accelerationYMSB = 0; cached_accelerationYLSB = 0; cached_accelerationZMSB = 0; cached_accelerationZLSB = 0; // *** Save state of all registers modified by the acceleration sensing code *** uint16_t original_P1DIR = P1DIR; uint16_t original_P1IE = P1IE; uint16_t original_P1OUT = P1OUT; uint16_t original_P1REN = P1REN; uint16_t original_P1SEL = P1SEL; uint16_t original_P1SEL2 = P1SEL2; set_UARTUCS(); setUARTPins(); uart_init(); // Enable intterupts // IE2 |= UCA0TXIE; // Enable the Transmit interrupt // IE2 |= UCA0RXIE; // Enable the Receive interrupt // _BIS_SR(GIE); // Enable the global interrupt ///////////////getAcceleration will make the MSP430 talks to the BNO055 getAcceleration(); // *** Restore all registers modified by the acceleration sensing code back to their previously saved state *** P1IE = original_P1IE; P1DIR = original_P1DIR; P1REN = original_P1REN; P1SEL = original_P1SEL; P1SEL2 = original_P1SEL2; P1OUT = original_P1OUT; set_UCS(); //set the clocks back } //Acceleration.c (main function ends here) ///////////////////////////////////////////////////////////////////////////// // Save value to transmit buffer // acceleration_location = malloc(6); // acceleration_location[0] = ((uint8_t*) &cached_accelerationXMSB)[0]; //check this (the order) // acceleration_location[1] = ((uint8_t*) &cached_accelerationXLSB)[0]; // see line 196~ // acceleration_location[2] = ((uint8_t*) &cached_accelerationYMSB)[0]; // acceleration_location[3] = ((uint8_t*) &cached_accelerationYLSB)[0]; // acceleration_location[4] = ((uint8_t*) &cached_accelerationZMSB)[0]; // acceleration_location[5] = ((uint8_t*) &cached_accelerationZLSB)[0]; //}
This will be part of a project to be loaded on a sensor node and the data should be transmitted wirelessly (you see that I commented the part f malloc that takes care of the data and put them in to the radio buffer). But the program is stuck when it gets to __bis_SR_register(LPM3_bits + GIE); // Enter LPM3 w/ int until Byte RXed.
I would like to get the program continue but I could not figure out how to do that. So would please help me with this? would you please suggest changes to be done? it is not necessarily to go to sleep at all, I just want the program to work. So please help me as I am stuck since a long time with this and this is affecting my studies as the major part of the project is to collect the data and analyze the data.
thank you
After a quick look, well, LPM3 will disable SMCLK. And SMCLK is the clock for the UART. So the UART has no clock to send or receive anything. And if nothing is sent/received, no interrupt is generated. And without an interrupt, the CPU will remain in LPM.
On 5x family, the USCI will request the clock when a start bit is detected (but on higher baudrates, it will be too late to properly receive the incoming byte). IIRC, the eUSCI will prevent SMCLK from being switched off at all, if active. Effectively turning LPM3 into LPM0-2.
I'm not 100% sure if on 2x family SMCLK is really unconditinally switched off (none of my 2x family projects used LPM), but this might be the source of your problems. Try again with LPM0 for a start.
Replacing LPM3 with LPM0 did not change the situation, still stuck and the sensor does not transmit.
But if I comment out this
if (uart.bufRXpnt == (uart.RXbuffer+uart.RXbuffer[1])) { __bic_SR_register_on_exit(LPM0_bits); }
in the RX ISR, and this
__bis_SR_register(LPM0_bits + GIE); // Enter LPM0 w/ int until Byte RXed
in the getAcceleration() function, then the sensor transmits, but weird data.
Would you please suggest a way to modify the code such that I do not use LPM(s) but still using interrupts? as you said, interrupts are very good in handing the UART data
Thank you
Thank you Jens-Mike
But what does the >& does?
uart.RXbuffer[1] will contain the length of incoming packet. So in my code I was checking if I received the whole packet. However, using >& checking resulted in the same thing. I am receiving the packets fine.
But my problem is not in UART reception or transmission. The problem I think in placing the LPM0. i.e after I do all transmission and reception via UART, I set back the clocks and pins and then put the MSP430 into LPM0. But what will make it wake to continue with the rest of the program (assuming that the received data from the BNO055 need to be transmitted wirelessly)?
OK, I did this
#include "msp430g2553.h" #include <stdio.h> char xLSB, xMSB, yLSB, yMSB, zLSB, zMSB; unsigned char setconfigmode[5]={0xAA, 0x00, 0x3D, 0x01, 0x00}; unsigned char setpowermode[5]={0xAA, 0x00, 0x3E, 0x01, 0x00}; unsigned char setAMGmode[5]={0xAA, 0x00, 0x3D, 0x01, 0x07}; unsigned char readACC[4]={0xAA, 0x01, 0x08, 0x06}; #define TXD BIT2 #define RXD BIT1 typedef unsigned char uint8_t; volatile uint8_t rx_counter = 0; #define BUFFER_SIZE 8 char RXbuffer[BUFFER_SIZE]; void set_UCS() {//------------------- Configure the Clocks -------------------// WDTCTL = WDTPW + WDTHOLD; // Stop the Watch dog DCOCTL = 0; // Select lowest DCOx and MODx settings BCSCTL1 = CALBC1_12MHZ; // Set range DCOCTL = CALDCO_12MHZ; // Set DCO step + modulation // DCO -> SMCLK (Default) IE1 &= 0xFD; /* Disable UCS interrupt */ return; } void setMSP430Pins() {//--------- Setting the UART function for P1.1 & P1.2 --------// P1SEL |= RXD + TXD ; // P1.1 = RXD, P1.2=TXD P1SEL2 |= RXD + TXD ; // P1.1 = RXD, P1.2=TXD return; } void uart_init(void){ P1SEL |= RXD + TXD ; // P1.1 = RXD, P1.2=TXD P1SEL2 |= RXD + TXD ; // P1.1 = RXD, P1.2=TXD UCA0CTL1 = UCSWRST; // Set UCSWRST (hold USCI in Reset state) UCA0CTL1 |= UCSSEL_2; // CLK = SMCLK // ------------ Configuring the UART(USCI_A0) ----------------// // 115200 BAUD, CLK=12MHz UCA0BR0 = 6; UCA0BR1 = 0; // //*ours: UCBRF = 8, UCBRS = 0, UCOS16 = 1 // // BITS| 7 6 5 4 | 3 2 1 | 0 | // UCAxMCTL = | UCBRFx | UCBRSx | UCOS16 | UCA0MCTL = 0x81; //this works fine UCA0CTL1 &= ~UCSWRST; // Clear UCSWRST to enable USCI_A0-UART UCA0CTL1 &= ~UCSYNC; IFG2 |= UCA0TXIFG; // preset IFG flag always left on } /////////////////////////UART send multiple Bytes//////////////////// void uartSend(unsigned char *pucData, unsigned char ucLength) { while(ucLength) { // Wait for TX buffer to be ready for new data while(!(IFG2 & UCA0TXIFG));//check if not set //if set, TX interrupt is pending // Push data to TX buffer UCA0TXBUF = *pucData; // Update variables ucLength--; //-- length of data left pucData++; //shift pointer } // Wait until the last byte is completely sent while(UCA0STAT & UCBUSY); //UCBUSY indicates if USCI transmitting or receiving } //////////////////////////////UART receive multiple Bytes/////// void USCI_ISR( void ) { RXbuffer[rx_counter] = UCA0RXBUF; if( ++rx_counter >= 2 ) { rx_counter = 0; IFG2 = ~UCA0RXIFG;//reset RX flag } } //¦----------------------------- Delay Function ---------------------------------------¦ void delay_ms(unsigned int ms) { unsigned int i; for (i = 0; i<= ms; i++) __delay_cycles(6000); // 6000 will give us 1ms } //¦----------------------------- Main -------------------------------------------¦ void main(void) { set_UCS(); uart_init(); //Make sure the BNO055 in config mode uartSend(setconfigmode,5); while(1) { while(!(IFG2 & UCA0RXIFG)); USCI_ISR(); } xMSB = RXbuffer[2]; xLSB = RXbuffer[3]; yMSB = RXbuffer[4]; yLSB = RXbuffer[5]; zMSB = RXbuffer[6]; zLSB = RXbuffer[7]; delay_ms(20); // delay_ms(20) }
However, code will still in the while(!(IFG2 & UCA0RXIFG));
I used while(1) as this is the only try that allowed me to get the received bytes and out them into the string RXbuffer. With out using the while(1) I will only get the 1st byte. Would anyone please check the RX ISR and tell me how to make it receive the whole packet and check the exit the ISR when receiving it in full?
Thank you
"But what does the >& does?"
It's not '>&' but rather '>' and '&'.
'&' is, not only the binary 'and' operator but also the unary reference operator: it gives the address of the following lvalue.
So "(&ptr[n])" gives the same value as "(ptr+sizeof(ptr[0])*n)": the address of the 2nd (index 1) element of the array.
The code is therefore checking whether the byte that contains the message size has been already received at all. A check that your original code was missing, so the size could still be 0 and the check would succeed even though nothing has been received yet.
UCA0CTL1 &= ~UCSYNC;
this line is superfluous, as
UCA0CTL1 = UCSWRST;
already did it. However, if this bit were set, clearing it would require setting SWRST again to initialite the UART for a completely different operation mode, as it would switch from SPI to UART mode, invalidating the current configuration.
I don'T see you setting IE2.UCA0RXIE, nor is GIE set anywhere, so your ISR is never called by an interrupt.
Well, you do it manually. Which wouldn't work if it were really declared as ISR (ISRs have a different entry/exit code and can't be called manually, even though the compiler might not complain)
When clearing SWRST in UART mode, UCA0TXIFG is always instantly set, no need to set it manually.
Your main code has code after the while(1) loop. The compiler shoudl compain about unreachabel code. However, if there were no while(1) loop, the main funciton would exit into the void, acting undefined (some compilers generate exit code that goes into LPM0, leaving interrutps enabled, some go into LPM4). YOu should have a while(1) or an LPM0; at the end of main (best a combination of both), so it never exits.
Finally, your 'ISR' has some flaws.
First, there is no need to manually clear RXIFG. You have read RXBUF, so it is already cleared. Worse, if it is not clear, this means that you have just received another byte after reading RXBUF, and claring RXIFG will make your code ignore it.
Then, if you got your second byte, rx_counter gets reset to 0. But if you still receive data, you will overwrite your received two bytes with the next two and so forth. I don't think this is intentional.
If you jsut want to receive two bytes, then check rx_counter right at the start of the function, and when it is >=2, then manually clear RXIFG, else read RXBUF and increment the counter. So you stop storing incoming bytes after the 2nd, as rx_counter will only count up to 2 and then 'lock' there.
Why your code hangs in the while? Maybe you have already received all the bytes, bu tsince you continue looping, you will enter the wait for RXIFG again and again and finally stall there when no further bytes are received.
If you want to receive 2 bytes and then continue, well, remove the IF case from your 'ISR'. It prevents detection of the end of reception outside if this function.
In the while(1) test for rx_count. And when it is >=2, do a break (break out of the while(1)).
Don't forget to put a while(1) at the end of main.
**Attention** This is a public forum