I would like to send string of chars from one proc (master) to another (slave) and then read string from a slave.
Currently im mixing up the arduino and LPC1788, using lpc as master and arduino as slave.
LPC sent's the string correctly which is received by the arduino in ISR. In loop function i check if all of the chars are received and then try to send string back. On LPC side ISR is not working for some reason. I have set SR as
SR = (1<<TNF) | (1<<RNE);
So i have put delay after sending the string from LPC and then initiate read from arduino.
What i see on LA for sending the string is:
but reading of string from Arduino looks odd (string should be "Pong\n", it is not always P that i received... it varies)
i guess majority of problem is within the sync of sending and reading of SPI buffer. How do i achieve that without functional ISR on LPC?
The SPI specification states that the CS (SSEL) line should be active during a frame and become inactive in between. NXP interpreted this as a word being one frame. This means that the CS as generated by the SSP block (the same goes for the legacy SPI) is only active during one transaction of up to 16 bits.
Note also that there is always a gap in between the words/frames being sent. So even when you fill the FIFO or use DMA you will see 16 clock pulses, a short delay and then 16 more pulses.
When using a GPIO pin as SSEL, please note you have to wait for SSEL assertion or de-assertion until the peripheral is idle.
Related
My setup is:
LPC1225FBD48/321
ext crystal: 16MHZ
PLL: MSEL=6, PSEL=2
UART0: CLKDIV=250 DL=1 DIVADDVAL=1 MULVAL=4
PLL gives mainclk=96MHz ; PCLK for UART is: 96MHz/250=384kHz ; Bit rate: 384kHz/(16x1x1.25)=19200
And it works, but only when LPC transmits. When LPC receives a character, it reports 2 characters received and sometimes framing error. Similar problem for other bit rates. At lower rates, like 2400, LPC reports single character received and sometimes framing error, but received character is not the same as I sent. It looks like Tx and Rx are using different clocks.
The UART works well when using bootloader with Flash Magic.
Has anyone encountered such a problem?
I finally found a solution. After setting CLKDIV = 50 and DL = 5, the UART became fully functional. While the documentation did not prohibit the previous set of parameters and both sets should give the same result, only the latter allows two-way communication.
Hi I am really new at embedded programming. I am using stm32cube IDE. I am trying to read a string to the DMA buffer but I need to implement start-marker as well as an end-marker. For example I only need to read the serial data in between '<' and '>' to the DMA buffer and when soon as it gets to the end-marker I want to call following call back function and process the data.
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
//Process Data
}
I want this to run in the background all the time. Is this possible?
No, the DMA controller cannot check the value of the data and stop or interrupt when a delimiter or marker byte is received. The DMA controller can only copy the received byte to memory. If you want to read variable length packets between delimiters then you need to use the CPU to check whether each byte is a delimiter. You can use the UART's RX interrupt to check for the delimiter as each byte is received.
DMA might be useful for receiving a continuous stream of bytes or a packet of known length.
I run this simplified program for SPI communication, running on the TI MSP430FR5969 on its corresponding launchpad MSP-EXP430FR5969, and set breakpoints just before TX and just after RX in CCS (Code Composer Studio). The breakpoints are labelled with comments.
My launchpad is not connected to anything. (Once I figure this out I intend to communicate it to some other device for real communication.)
I do not expect to receive any data because the launchpad is not connected to anything. But I receive exactly one zero for every send. The breakpoints are hit in alternate order starting with the first TX breakpoint.
Why am I receiving data? Is it because I need to enable pullup registers on some of the pins? I believe the launchpad itself uses the USCI "A" module(s) so the "B" module that I am using should have nothing connected to it.
#include <msp430.h>
int main(void) {
WDTCTL = WDTPW | WDTHOLD;
P1SEL0 &= ~BIT3; // UCB0STE
P1SEL0 &= ~BIT6; // UCB0SIMO
P1SEL0 &= ~BIT7; // UCB0SOMI
P2SEL0 &= ~BIT2; // UCB0CLK
P1SEL1 |= BIT3; // UCB0STE
P1SEL1 |= BIT6; // UCB0SIMO
P1SEL1 |= BIT7; // UCB0SOMI
P2SEL1 |= BIT2; // UCB0CLK
PM5CTL0 &= ~LOCKLPM5;
CSCTL0_H = CSKEY_H;
CSCTL1 &= ~DCORSEL;
CSCTL1 = (CSCTL1 & ~0x000e) | DCOFSEL_0; // 1 MHz
CSCTL3 |= DIVA__1 | DIVS__1 | DIVM__1; // clock dividers = 1
CSCTL0_H = 0;
UCB0CTLW0 |= UCSWRST;
UCB0CTLW0 |= UCCKPH;
UCB0CTLW0 |= UCCKPL;
UCB0CTLW0 |= UCMSB;
UCB0CTLW0 |= UCMST;
UCB0CTLW0 |= UCMODE_2;
UCB0CTLW0 |= UCSYNC;
UCB0CTLW0 |= UCSSEL__SMCLK;
UCB0CTLW0 |= UCSTEM;
// UCB0STATW |= UCLISTEN; // OK, if enabled i receive what i send
UCB0CTLW0 &= ~UCSWRST;
UCB0IE |= UCRXIE;
_enable_interrupts();
_delay_cycles(100000);
int send = 0;
while (1) {
while (!(UCB0IFG & UCTXIFG));
UCB0TXBUF = send; // BREAKPOINT 1
send = (send + 1) % 100;
_delay_cycles(100000);
}
return 0;
}
#pragma vector = USCI_B0_VECTOR
__interrupt void isr_usci_b0 (void) {
static volatile int received = 0;
switch (__even_in_range(UCB0IV, USCI_SPI_UCTXIFG)) {
case USCI_NONE:
break;
case USCI_SPI_UCRXIFG:
received = UCB0RXBUF;
UCB0IFG &= ~UCRXIFG; // BREAKPOINT 2
_no_operation();
break;
case USCI_SPI_UCTXIFG:
break;
}
}
The SPI peripheral does two things if MISO and MOSI are enabled (CLK enabled as well, of course). Assuming Master mode operation, it clocks out data from the TX shift register on the MOSI line and simultaneously clocks in data to the RX shift register from the MISO line.
In your circuit, the MISO input is hanging since you have not enabled either pull-up or pull-down internal resistances. Thus, observing 0x00 would not be out of the ordinary. If you had enabled the pull-up resistance, then you would have seen 0xFF in the receive buffer.
Another rule of thumb:
If you are using the peripheral functions then configure the GPIO pins of the MSP430 as output/input. (i.e. MOSI, CLK = output, MISO = input for SPI master mode)
Answer to the questions in the comments:
The MSP430 is configured in the listed code to be the SPI master. I see little point in the using a dedicated RX interrupt service routine, unless you want the controller to do something else in the time between shifting data from the TX buffer to the shift register and shifting data from the RX shift register to the RX buffer, i.e. one "byte" transfer period. You could as well have polled for the RX interrupt as you have for the TX interrupt. But you must wait for the RX interrupt.
Excerpt from the user guide:
The eUSCI initiates data transfer when data is moved to the transmit data buffer UCxTXBUF. The UCxTXBUF data is moved to the transmit (TX) shift register when the TX shift register is empty, initiating data transfer on UCxSIMO starting with either the MSB or LSB, depending on the UCMSB setting. Data on UCxSOMI is shifted into the receive shift register on the opposite clock edge. When the character is received, the receive data is moved from the receive (RX) shift register to the received data buffer UCxRXBUF and the receive interrupt flag UCRXIFG is set, indicating the RX/TX operation is complete.
A set transmit interrupt flag, UCTXIFG, indicates that data has moved from UCxTXBUF to the TX shift register and UCxTXBUF is ready for new data. It does not indicate RX/TX completion.
To receive data into the eUSCI in master mode, data must be written to UCxTXBUF, because receive and transmit operations operate concurrently.
The client will not send data by itself to the MSP430. The client device may need some time to execute the command the master just sent. Typically an "erase flash" command for SPI Flash chips.
In this case the master, i.e. MSP430, must poll the client device to see if it has data to send/completed the command. This is done typically either by polling a status register of the client device (or by using a dedicated IRQ interrupt). i.e. the client signals "completion of command"/"availability of data" via the status byte (or IRQ interrupt). On this event, the master could read out data from the client.
At first glance it may seem rather counter intuitive that data (dummy bytes) needs to be written in order to read data - perhaps your source of confusion as well :)
Perhaps reading about an SPI client may help. For example this SPI memory.
The SPI peripheral transmits a bit and receives a bit for every clock cycle. Instead of wondering how some unconnected device has sent a byte, think that your SPI peripheral has clocked in a receive byte even though nothing is connected. The byte you receive is 0 because the MISO line happens to be low while nothing is connected.
The SPI peripheral does not know the meaning of the data and does not know how many bytes must be transmitted and received for any particular command. It's up to your application to know when to transmit and receive dummy bytes. For example, if the slave responds to a command in the next byte then your application has to transmit two bytes (the command byte followed by a dummy byte) and at the same time receive two bytes (a dummy byte, followed by the response). Some slaves may send a generic status byte instead of a dummy byte as the first byte of all responses. It's up to your application to use or ignore the status byte.
The MSP430's SPI documentation is not going to tell you when you need to send/receive dummy bytes. You'll have to read the SPI documentation for the slave device for that information. Each slave may have different requirements. Some slaves my receive a command byte and send a reply. Other slaves may receive a command and address byte before sending a reply. Some slaves may reply with multiple bytes. You'll have to program your application to transmit/receive the appropriate number of bytes.
There are no stop bits. The master is both transmitting and receiving with every clock. If you want to stop receiving then stop transmitting. If you want to continue receiving then transmit dummy bytes.
Yes, you should use the RX interrupt. The RX interrupt indicates that it is safe for your application to read the received byte from the RX register. The SPI peripheral is shifting receive bits into a shift register with each clock. But after a byte has been received the SPI peripheral still has to copy the contents of the shift register to the RX register and then set the RX interrupt. You shouldn't assume that the received byte can be read from the RX register until the RX interrupt is indicated.
The behavior you describe is to be expected. With SPI, it is movement on the clock line that indicates the presence of data. The input line can be idle, and data will be received because, in order to send a byte, the clock must be toggled back and forth to latch the transmitted data, but at same time, data is latched into the receive buffer.
An SPI bus is intended to be a closed pathway. The TX line from your processor goes out and is daisy-chained to one or more slave devices and then looped back to your RX pin. Every transition on the clock line drives a data bit. This means that for every transition your hardware will shift one bit into your receive buffer. It's up to your code to know how many of those bits to discard before you start reading real data.
You are reading 0's because nothing is driving the RX pin. When you're connected to a real device, the first several bytes you send will also likely generate 00's on your RX pin. Usually you'll have to send some sort of command byte to the slave device which then will start sending real data. The length of that command should be discarded because the slave will not have started driving its output pin until the command byte (word, string, whatever) is complete.
The Problem: I send one value into a UART and nulls emerge on the other UART.
--- Details ---
These are both PIC processors (PIC24 and PIC32)
They are both hard wired onto a printed circuit board.
They are communicating, each via one of the UART modules which reside within them.
They are (ostensibly; according to docs) both configured for 115200 bps, 8-N-1
No handshaking, no CTS enabled, no RTS enabled; I'm just putting bytes on the wire and out they go.
(These are short little 4-byte commands and responses which fits pretty neatly)
The PIC32 is going 80 MHz.
The PIC24 has F[cy] = 14745600
i.e., it is going 14.7456 MHz
The PIC24 sends four bytes (a specific command sequence)
When I set a breakpoint at the Interrupt Service Routine for the UART, The PIC32 shows nulls, then I am seeing repeated hits on the (PIC32 code) breakpoint after the first four, and I continue to see nulls (which makes sense since the PIC24 is not sending anything)
i.e., the UART appears to be repeatedly generating interrupts when there is no reason
I did not write the code on the PIC32 side, and I am learning daily how it works.
Then I let the code just run, and I inevitably wind up on a line that says
52570 1D01_335C 9D01_335C _general_execption_handler sdbbp 0x0
When I get there,
The cause register holds 0080181C
The EPC register holds 9D00F228
The SP register holds 9F8FFFA0
This happened like clockwork, so I got suspicious of the __ISR that would not stop. MpLab showed me this...
432:
433: //*********************************************************//
434: void __ISR(_UART1_VECTOR, ipl5) IntUart1Handler(void) //MCU communication port
435: {
9D00F204 415DE800 rdpgpr sp,sp
9D00F208 401A7000 mfc0 k0,EPC
9D00F20C 401B6000 mfc0 k1,Status
9D00F210 27BDFF88 addiu sp,sp,-120
9D00F214 AFBA0074 sw k0,116(sp)
9D00F218 AFBB0070 sw k1,112(sp)
9D00F21C 7C1B7844 ins k1,zero,1,15
9D00F220 377B1400 ori k1,k1,0x1400
9D00F224 409B6000 mtc0 k1,Status
9D00F228 AFBF0064 sw ra,100(sp) ;<<<-------EPC register always points here
9D00F22C AFBE0060 sw s8,96(sp)
9D00F230 AFB9005C sw t9,92(sp)
9D00F234 AFB80058 sw t8,88(sp)
9D00F238 AFAF0054 sw t7,84(sp)
9D00F23C AFAE0050 sw t6,80(sp)
9D00F240 AFAD004C sw t5,76(sp)
9D00F244 AFAC0048 sw t4,72(sp)
9D00F248 AFAB0044 sw t3,68(sp)
9D00F24C AFAA0040 sw t2,64(sp)
9D00F250 AFA9003C sw t1,60(sp)
9D00F254 AFA80038 sw t0,56(sp)
9D00F258 AFA70034 sw a3,52(sp)
9D00F25C AFA60030 sw a2,48(sp)
9D00F260 AFA5002C sw a1,44(sp)
9D00F264 AFA40028 sw a0,40(sp)
9D00F268 AFA30024 sw v1,36(sp)
9D00F26C AFA20020 sw v0,32(sp)
9D00F270 AFA1001C sw at,28(sp)
9D00F274 00001012 mflo v0
9D00F278 AFA2006C sw v0,108(sp)
9D00F27C 00001810 mfhi v1
9D00F280 AFA30068 sw v1,104(sp)
9D00F284 03A0F021 addu s8,sp,zero
I look a little more closely at the numbers, and I see that at that time, if we add 100 (0x64) to FFA0 (the bottom 16 bits of the SP) we get 0x10004, which I am guessing is 4 too much.
PIC Manual DS61143E-page 50 says that that nomenclature means, SW Store Word Mem[Rs+offset> = Rt and other experts have told me that the cause register is telling me that the EXCCODE bits are 7 which is the code for a bus exception on load or store.
Or, I'm totally guessing here (would love to get some experts' knowledge on this) something is not clearing something and I'm encountering infinite recursion on an int handler.
All of this is starting to make sense.
THE QUESTION
Could someone please suggest the most common reasons for an int like this to be repeatedly hitting me ?
Does anyone see any common relationship between the bogus nuls coming from the UART which could somehow be connected with this endlessly generated int ? Am I even on the right track ?
In your answer, please tell me how to acknowledge the Int from the UART. I know how I do that in the PIC24 (I wrote that code totally, in ASM) but I don't know how this is done in in C on the PIC32. Assembly will be fine. I'll inline it. I'm working with code I didn't write here, and I thank you for your answers
What is the most common reason that the UART (#1, in this case) would be repeatedly generating interrupts ?
The most common reason an interrupt subroutine is called over and over is that the interrupt request is never acknowledged in the routine.
Are you sure you clear the corresponding IRQ bit?
To ease UART debugging you should first connect the UART to a PC and make sure your target can communicate both ways with the PC. With two targets at the same time, you can't determine on which one the problem is apart from inspecting signals with a scope.
On many devices an interrupt must be explicitly cleared to prevent the ISR from simply re-entering when complete.
In most cases a UART will have status bits that indicate the source of the interrupt, knowing that might tell you something, but not telling us makes it difficult to help you. You can inspect the UART registers directly in the debugger, however in some devices the act of reading a bit may in fact clear a bit, and that is true in the debugger too, so be aware of that possibility (check the data sheet/user manual).
Some UARTS require their transmitter to be explicitly switched off to stop transmitting nulls, while others are triggered automatically when data is placed in the tx register and stop after the necessary number of bits are shifted out. Again check the data sheet/manual for the part. If the PIC32 code is known to be working, then since this possible error would be with the PIC24 code, it seems to fit. You can check this simply by using an oscilloscope on the Tx line from the PIC24, if it is transmitting, you will see at least start/stop bit transitions (framing). If there is nothing, then the problem is probably at the PIC32 end.
While you have the scope out, you can check that the bit timing is correct and that you are actually transmitting at 115200. It is easy to get the clocking wrong, and that should be your first check. If the baud rate is incorrect, the PIC32 will likely generate framing error interrupts, which if not handled may persist indefinitely.
Another possibility is that after transmission the PIC24 leaves the line in the "break" state, and that the PIC32 UART is generating "line-break" interrupts. That is why it is important to look at the UART status registers to determine the interrupt cause.
As you can see, there are many possibilities; I think I have covered the most likely ones, but more methodical debugging effort and information gathering on your part is required. I hope I have guided you in this too.
There were the three root causes which were in place...
The interrupt priority level was set at value 6 in the initialization code for UART1
The first line of the interrupt service routine was coded with an interrupt priority level of 5
The first three bytes of UART data were disappearing from the data stream (this is still unsolved)
Here's the not-so-obvious way they were causing the problem
First three bytes never appeared
Fourth byte did appear
Interrupt hit (as level 6) and invoked __ISR routine
__ISR was acting as ipl5 agent
First instruction executed (possibly more, I couldn't debug that accurately)
As soon as the first instruction finished, the "higher" priority 6 interrupt immediately kicked in
This resulted in the same interrupt again
The process repeated itself infinitely.
In short order, Stack Overflow resulted
The Fix
Make sure these two lines of code agree with each other...
The IPL line in the init code, wrong way then the right way
//IPC6bits.U1IP=6; //// Wrong !!! Uart 1 IPL should not be 6 !!!
IPC6bits.U1IP=5; //// Uart 1 IPL = 5 Correct way; matches __ISR
Interrupt Service Routine
void __ISR(_UART1_VECTOR, ipl5) IntUart1Handler(void) //// Operating as IPL 5
:
:
:
:
Poor design decision. If both are on same board SPI would have been more feasible and a lot faster.
I have two PIC32MX microcontrollers that are connected over a 1.53MHz SPI bus with Chip Select. I am having trouble getting my slave side interrupt service routine to transmit data correctly. As a test case, I'm having the master send out two bytes (0x01, 0x00) every 10 ms. The slave is supposed to receive the 0x01 command id and respond with a 0x02 when the master sends the 2nd byte (the dummy 0x00).
Ideally each transfer should look like this.
Master Slave
0x01 0x00
0x00 0x02
I'm really not sure where to start with the slave interrupt though. I'm using a fifo buffer called airsysTx to hold data that needs to be shifted out the next time the master makes a request. The slave receives the 0x01 from the master just fine and writes 0x02 to the fifo buffer when it does. I'm not sure how to code the interrupt so that it will be sure to transmit correctly. The code I have below is a good start, but it's wrong. Suggestions?
/*******************************************************************************
* Interrupt service routine for SPI3 interrupts from Air MCU.
* The user's code at this vector should perform any application specific
* operations and MUST clear the SPI3 interrupt flags before exiting.
******************************************************************************/
void __ISR(_SPI_3_VECTOR, ipl7) _SPI3Interrupt()
{
BYTE MasterCMD;
SET_D1();//Set debug LED
// RX INTERRUPT
if(IFS0bits.SPI3RXIF) // receive data available in SPI3BUF Rx buffer
{
MasterCMD = SPI3BUF;
if(AirCMD == 0x01)
{
airsysTxFlush();
airsysTxWrite(0x02);
}
}
//Transmit data if needed.
if(SPI3STATbits.SPITBE)
{
if(!airsysTxIsEmpty())
{
SPI3BUF = airsysTxRead();
}
else
{
//Else write 0 to the tx buffer to clear the spi shift reg
SPI3BUF = 0x00;
}
}
IFS0bits.SPI3RXIF = 0;
IFS0bits.SPI3TXIF = 0;
IFS0bits.SPI3EIF = 0;
SPI3STATbits.SPIROV = 0;// clear the Overflow
CLEAR_D1();//CLEAR Debug LED
} // end ISR
What this code is actually transmitting is something like this:
Ideally each transfer should look like this.
Master Slave
0x01 0x02
0x00 0x01
Generally you can't write a slave SPI driver to interact in the way you describe because you can't control the timing precisely as a slave. What generates your ISR, is it Rx of first byte from master or assertion of chip select?
As the slave, you need to have set up the data bytes you want to transmit before the master starts the transaction. You usually don't have time to react to the first byte. There are a couple of ways to do this:
1) You could use a protocol where master does a 1 or 2 byte write-only transaction that tells the slave what it wants to read. Then master waits a few milliseconds to allow the slave to prepare the response. Then master does a read-only transaction to get the slave response.
2) If using DMA or FIFO, slave preloads the first padding byte(s) into the fifo before master starts the transaction. Then as you get the ISR you put the remaining response data into the fifo (without a flush). You need to have enough pad bytes to accommodate the slave ISR latency in forming the response. So for example, you may define your protocol where master knows that the first N bytes of response are pad bytes, followed by response data. Padding requirement would depend on your master clock speed and slave CPU speed/interrupt latency.