STM32F407 SPI While Reading Datas of LIS3DSH - spi

uint8_t SPI_Rx(uint8_t address)
{
GPIO_ResetBits(GPIOE,GPIO_Pin_3);
address = (0x80) | (address);
while(!SPI_I2S_GetFlagStatus(SPI1,SPI_FLAG_TXE));
SPI_I2S_SendData(SPI1,address);
while(!SPI_I2S_GetFlagStatus(SPI1,SPI_FLAG_RXNE));
SPI_I2S_ReceiveData(SPI1);
while(!SPI_I2S_GetFlagStatus(SPI1,SPI_FLAG_TXE));
SPI_I2S_SendData(SPI1,0x00);
while(!SPI_I2S_GetFlagStatus(SPI1,SPI_FLAG_RXNE));
SPI_I2S_ReceiveData(SPI1);
GPIO_SetBits(GPIOE,GPIO_Pin_3);
return SPI_I2S_ReceiveData(SPI1);
Hi, what you see is SPI reading functions for LIS3DSH sensor. First of all, After I send adress knowledge, SPI RX buffer receives datas of LIS3DSH sensor. But then why does it need to receive data of LIS3DSH sensor by sending "0x00" ? Briefly, why do we need to send else data again while we already received datas? Ahead of time ,Thanks.

When reading data from a register of the LIS3DSH, the entire SPI transaction is two bytes long:
Byte 1: The master sends the register address (incl. a read/write flag) to the sensor.
Byte 2: The sensor sends the register value to the master.
However, SPI is a full-duplex protocol. For each bit and byte, both the master and the slave (sensor) send data. So the real communication in fact looks like so:
Byte 1
Master sends register address.
Slave sends 0 or any random value.
Byte 2
Master sends 0.
Slave sends register value.
This is what you see in the code:
while(!SPI_I2S_GetFlagStatus(SPI1,SPI_FLAG_TXE)); // Wait for SPI bus to be ready
SPI_I2S_SendData(SPI1,address); // Submit byte 1 to be sent
while(!SPI_I2S_GetFlagStatus(SPI1,SPI_FLAG_RXNE)); // Wait for byte 1 from slave
SPI_I2S_ReceiveData(SPI1); // Retrieve byte 1 from slave and ignore it
while(!SPI_I2S_GetFlagStatus(SPI1,SPI_FLAG_TXE)); // Wait for SPI bus to be ready
SPI_I2S_SendData(SPI1,0x00); // Send 0 as byte 2
while(!SPI_I2S_GetFlagStatus(SPI1,SPI_FLAG_RXNE)); // Wait for byte 2 from slave
SPI_I2S_ReceiveData(SPI1); // Retrieve byte 2 and ??
GPIO_SetBits(GPIOE,GPIO_Pin_3); // Deassert CS?
return SPI_I2S_ReceiveData(SPI1); // Retrieve byte 2 again and return it
The last part is somewhat strange. SPI_I2S_ReceiveData() is called twice at the end probably assuming that it will return the same value twice. It would probably be cleaner if it was called only once.

Related

STM32F4-Discovery UART receive by DMA with included start-marker as well as an end-marker

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.

how to write code for transfer data from internal memory via SPI Master to 2 slave

I receive data from USB to the internal memory of Atxmega 128A1
if ( (SWITCHPORTL.IN & PIN1_bm) == 0 )
{
j = 0;
while (j < NUM_BYTES)
{
// Wait till there is unread data in the receive buffer
while((USART.STATUS & USART_RXCIF_bm) == 0 ){};
// Read out the received data
__far_mem_write(j+SDRAM_ADDR, USART.DATA);
if (j == (NUM_BYTES-1))
{
// Toggle LED 1
LEDPORT.OUTTGL = PIN1_bm;
}
j++;
}
}
How to write code for transfer data from internal memory via SPI Master to two slaves such that odd and even byte of data should be send separately to two slaves? How to initiate master to two slaves(multiple slaves)?
I think this is possible mostly when both the slave will understand data in a similar format, as in have same configuration for CPOL and CPHA. You can select one particular slave by enabling the CS pin respectively. So, your code can look like:
initMaster();
selectSlave1(); //Make CS1 low and CS2 high
spiTransmit(data1); //transmit odd byte
selectSlave2(); //Make CS2 low and CS1 high
spiTransmit(data2); //transmit even byte
Since both slaves are connected to the same bus that only can be transfer one data at a time you have two options to choose from:
implement a simple protocol so that each slave does know, which byte belongs to it. (example: one byte header with 6 bit length and 2 bit receiver code or (1 - slave 1, 2 slave 2 - 3 both slaves even/odd)
use slave select pins and transfer a byte and make sure you do not send the next and deselect the first receiver until the old was send (calculate clock cycles how long would it take and nop them or use them for other usefull stuff))

Every SPI send results in receiving a 0 on MSP430

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.

lpc1788 ssp (SPI) - proc to proc communication

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.

Implementing SPI slave ISR on PIC32?

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.