How do I know if the SPI is correctly working, if I can only check on the master's board? - embedded

I have an STM32F429ZI Nucleo board (for SPI master and UART to check everything's working alright) and an EVB-LAN9252-SPI board(for SPI slave).
I have to check if the SPI is correctly working, but it seems that I can't debug or check on the slave's side.
Shown below is the test code that I worked on the STM32F429ZI Nucleo board to check if the SPI is working correctly. SPI1 and SPI4 is configured in one board.
while (k < 32)
{
HAL_UART_Transmit(&huart4, &SPI1_Buffer_Tx[k], 1, 100);
k++;
}
k = 0;
while (k < 32)
{
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_9, GPIO_PIN_RESET); // this GPIO is connected to hardware NSS
HAL_SPI_Transmit(&hspi1, &SPI1_Buffer_Tx[k], 1, 100);
HAL_SPI_Receive(&hspi4, &SPI4_Buffer_Rx[k], 1, 100);
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_9, GPIO_PIN_SET);
k++;
}
k = 0;
while (k < 32)
{
HAL_UART_Transmit(&huart4, &SPI1_Buffer_Tx[k], 1, 100);
k++;
}
k = 0;
while (k < 32)
{
HAL_UART_Transmit(&huart4, &SPI4_Buffer_Rx[k], 1, 100);
k++;
}
In this case the UART shows me such answer
abcdefghijklmnopqrstuvwxyzABCDEF //what was originally in the transmit buffer
bcdefghijklmnopqrstuvwxyzABCDEF //what was received in the receive buffer
Maybe this was possible because I could read on the slave's side, with such code
HAL_SPI_Receive(&hspi4, &SPI4_Buffer_Rx[k], 1, 100);
Now back to the original project.
At first I assumed that the data transmitted from the master should circulate in the slave somehow and transmit back to the master, so that if I read from the master I should get the original data, but in backwards.
so this was the code.
while (k < 32)
{
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_14, GPIO_PIN_RESET);
HAL_SPI_Transmit(&hspi1, &SPI1_Buffer_Tx[k], 1, 100);
HAL_SPI_Receive(&hspi1, &SPI1_Buffer_Rx[k], 1, 100);
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_14, GPIO_PIN_SET);
k++;
}
and what I received from the master is 32 0xFFs.
I'm not sure where I'm wrong about.
Does the data actually circulate in the slave's side and is it just me doing something wrong?
The data seems to be correctly transmitted, but the slave hasn't been ordered to transmit anything back to the master. That's why I can't receive meaningful data from the master.
2-1. If so, how do I know that the slave has received the data correctly?
2-2. How do I order the slave to transmit back to the master some meaningful data? I can only debug my code on the master's board.

Thanks for your kind comments!
It took a whole month for me to get this work done, and I'm sure there'll be newbies like me in the future, so..
As in the LAN9252 Datasheet page 302/329 and 303/329, you can send "0x0050" to receive "0x92520001", and "0x0064" to receive "0x87654321".
the way you send the data is kinda delicate, and that was the part I kept failing. I was (and am) not fully understanding the principles of SPI communication and you're gonna need an oscilloscope with multiple probes(It took me only 2 days after using the oscilloscope, because before then I couldn't check what I was doing).

Related

The SPI shift register does not always send all data to the RX BUFFER (TI microcontroller)

I have connected 2 TI controllers via SPI. The TMS320F28055 controller is my master and the TMS320F2885 controller is my slave. I want to send complete data to the slave via spi. The data always ends up successfully in the SPIDAT register, i.e. the shift register. The shift register should then send the data to the SPIRXBUF - Buffer. Sometimes the data is successfully sent to the buffer and sometimes not it's always very random I've tried a lot. I don't use a FIFO. Does anyone know how I can fix the problem.
I made a table showing the data in the master and slave registers. I also send the configuration of the slave and master.
void spi_init(void)
{
SpiaRegs.SPICTL.all = 0x000E; //Normal SPI clocking scheme(Data in latch on rising edge)master, 4-pin option, No interrupt
SpiaRegs.SPICTL.bit.CLK_PHASE = 1; //1
SpiaRegs.SPIBRR = 0x0077; //BateRate 0.5MHz
SpiaRegs.SPICCR.all = 0x0087; //SPI is ready to transmit or receive the next character.
SpiaRegs.SPICCR.bit.CLKPOLARITY = 0; //0
SpiaRegs.SPIPRI.bit.FREE = 1;
}
This is the code from my master, I use the TMS320F28055:
void spi_init(void)
{
SpiaRegs.SPICCR.bit.SPISWRESET = 0;
SpiaRegs.SPICTL.all = 0x000A; //8 //Normal SPI clocking scheme(Data in latch on rising edge)slave, 4-pin option, No interrupt
SpiaRegs.SPICTL.bit.CLK_PHASE = 1; //1
SpiaRegs.SPIBRR = 0x0077; //BateRate 0.5MHz ist für den Slave nicht notwendig
SpiaRegs.SPICCR.all = 0x0087; //SPI is ready to transmit or receive the next character.
SpiaRegs.SPICCR.bit.CLKPOLARITY = 0; //0
SpiaRegs.SPICTL.bit.SPIINTENA = 1 ;
SpiaRegs.SPICTL.bit.OVERRUNINTENA = 1 ;
SpiaRegs.SPIPRI.bit.FREE = 1;
SpiaRegs.SPICCR.bit.SPISWRESET=1;
}
And this is the code from my slave TMS320F28035.
I'm using an interrupt here, but I've also tried it without an interrupt.
uint16_t pdata = 0x1234;
int dataH, dataL;
dataH = 0;
dataL = 0;
dataH = (pdata >> 8);
dataL = (pdata & 0x00FF);
spi_xmit(dataH);
spi_xmit(dataL);
And with that I send example data, in this case it would be the 0x1234. When I send it it arrives successfully in the shift register and buffer. But if I want to send it more often, the shift register does not completely shift the data into the buffer. To check I debug both microcontrollers at the same time. By the way, I send 8 bits twice in a row. the buffer has a size of 16 bits.

Why can't I detect start condition when to bitbang-read/sniff I2C port? stm32

I am trying to bitbang-read or rather sniff an I2C port. I have successful I2C communication between a master I2C device and a Nucleo stm32F401 board. Nucleo slave sending using DMA. Then I am using 2 pins from the same Nucleo to try to sniff the communication. Both of the pins are configured as inuputs with pull-ups.
I read the pins' value like this:
while (1) {
uint8_t CLK_val = HAL_GPIO_ReadPin(GPIOB, 1);
uint8_t SDA_val = HAL_GPIO_ReadPin(GPIOB, 2);
//And then I try to detect start condition like this:
if (CLK_val == GPIO_PIN_RESET && SDA_val == GPIO_PIN_RESET){
//Some code
}
//More code
};
If I manually pull the pins down, touching both of them with a cable connected to ground, the condition is met. But the I2C transaction doesn't trigger the condition even though the transaction is being successful and thus the pins must have been pulled down during the transaction.
Why would the condition not be met during the I2C transaction?
AN I2C start condition is a falling edge of data while clock remains high. To detect it from GPIO you need to do something like:
CLK_val_before = HAL_GPIO_ReadPin(GPIOB, 1);
SDA_val_before = HAL_GPIO_ReadPin(GPIOB, 2);
CLK_val_after = HAL_GPIO_ReadPin(GPIOB, 1);
SDA_val_after = HAL_GPIO_ReadPin(GPIOB, 2);
if ((CLK_val_before == GPIO_PIN_SET)
&& (SDA_val_before == GPIO_PIN_SET)
&& (CLK_val_after == GPIO_PIN_SET)
&& (SDA_val_after == GPIO_PIN_RESET))
{
// Some code
}

ATMEGA2561 WINC1500 Driver implementation SPI problem

I am trying to implement the WINC1500 MLA Driver to work with the ATMEGA2561 MCU and I have written my driver code and it's stuck on the line "while((SPSR & (1 << SPIF)) == 0);" in the m2mStub_SpiTxRx function.
I have no idea why it's not progressing through. I'm using the jumpstart ImageCraft IDE for this project.
Here's the implementation of it
void m2mStub_SpiTxRx(uint8_t *p_txBuf,
uint16_t txLen,
uint8_t *p_rxBuf,
uint16_t rxLen)
{
uint16_t byteCount;
uint16_t i;
// Calculate the number of clock cycles necessary, this implies a full-duplex SPI.
byteCount = (txLen >= rxLen) ? txLen : rxLen;
DEBUGOUTF("Calculate the number of clock cycles\n");
DEBUGOUTF("byteCount %d", byteCount, "\n");
DEBUGOUTF("txLen %d", txLen, "\n");
DEBUGOUTF("rxLen %d", rxLen, "\n");
// Read / Transmit.
for (i = 0; i < byteCount; ++i)
{
// Wait for transmitter to be ready. (This is causing the entire thing to crash)
while((SPSR & (1 << SPIF)) == 0);
// Transmit.
if (txLen > 0)
{
// Send data from the transmit buffer.
SPDR = (*p_txBuf++);
--txLen;
}
else
{
// No more Tx data to send, just send something to keep clock active.
SPDR = 0x00U;
}
// Wait for transfer to finish.
while((SPSR & (1 << SPIF)) == 0);
// Send dummy data to slave, so we can read something from it.
SPDR = 0x00U;
// Wait for transfer to finish.
while((SPSR & (1 << SPIF)) == 0);
// Read or throw away data from the slave as required.
if (rxLen > 0)
{
*p_rxBuf++ = SPDR;
--rxLen;
}
else
{
// Clear the registers
volatile uint8_t reg_clear = 0U;
reg_clear = SPDR;
(void)reg_clear;
}
}
}
I don't have enough information to say for sure, but my assumption is that your SPI connection is not set up correctly.
In particular, I guess you forgot to set /SS as output, same as this problem or this.
In the datasheet it says:
Master Mode When the SPI is configured as a master (MSTR in SPCR is
set), the user can determine the direction of the SS pin.
If SS is configured as an output, the pin is a general output pin
which does not affect the SPI system. Typically, the pin will be
driving the SS pin of the SPI slave.
If SS is configured as an input, it must be held high to ensure Master
SPI operation. If the SS pin is driven low by peripheral circuitry
when the SPI is configured as a master with the SS pin defined as an
input, the SPI system interprets this as another master selecting the
SPI as a slave and starting to send data to it. To avoid bus
contention, the SPI system takes the following actions:
The MSTR bit in SPCR is cleared and the SPI system becomes a slave. As a result of the SPI becoming a slave, the MOSI and SCK pins become
inputs.
The SPIF flag in SPSR is set, and if the SPI interrupt is enabled, and the I-bit in SREG is set, the interrupt routine will be executed.
Thus, when interrupt-driven SPI transmission is used in master mode,
and there exists a possibility that SS is driven low, the interrupt
should always check that the MSTR bit is still set. If the MSTR bit
has been cleared by a slave select, it must be set by the user to
re-enable SPI master mode.
So, you just need to configure the /SS pin as output and set to high in your init code, this should solve your problem:
DDRB |= (1 << PB0); // Set /SS (PB0) as output
PORTB |= (1 << PB0); // Set /SS (PB0) high

How Can I Establish UART Communication between 2 Stm32 and produce PWM signal

Edit: I solved UART communication problem but I have new problem getting pwm signal after receiving Transmit Data. I can blink led I can drive relay with transmitted data but I could not produce PWM signal.
maps(120, 1, 1, 250, RxData[4]);
ADC_Left = Yx; __HAL_TIM_SET_COMPARE(&htim2,TIM_CHANNEL_1,ADC_Left);
I used __HAL_TIM_SET_COMPARE function but it doesnt work. I can observe ADC_Left’s value on Debug site but its not work.
I am trying to realize UART communication between 2 stm32. I know there are several topic related with but my question focused another one.
I am reading 2 adc value on stm32 which is only transmit these value and other one only receive these 2 adc value. To do this
MX_USART1_UART_Init();
__HAL_UART_ENABLE_IT(&huart1, UART_IT_RXNE); // Interrupt Enable
__HAL_UART_ENABLE_IT(&huart1, UART_IT_TC);
char TxData1[10];
..............
TxData1[0] = 0xEA;
TxData1[1] = wData.Byte_1;
TxData1[2] = wData.Byte_2;
TxData1[3] = wData.Byte_3;
TxData1[4] = wData.Right_Adc_Val;
TxData1[5] = wData.Left_Adc_Val;
TxData1[6] = wData.Byte_6;
for(uint8_t i = 1 ; i < 7; i++)
{
wData.Checksum = wData.Checksum + TxData1[i];
}
wData.Checksum_H = (wData.Checksum >> 8)&0xFF;
wData.Checksum_L = (wData.Checksum)&0xFF;
TxData1[7] = wData.Checksum_H;
TxData1[8] = wData.Checksum_L;
TxData1[9] = 0xAE;
HAL_UART_Transmit_IT(&huart1,(uint8_t*) &TxData1,10);
............
This block sent them I can observate them on Debug screen and using TTL module's Tx Rx pins.
MX_USART1_UART_Init();
__HAL_UART_ENABLE_IT(&huart1, UART_IT_RXNE); // Interrupt Enable
__HAL_UART_ENABLE_IT(&huart1, UART_IT_TC);
char RxData[10];
while(1){
HAL_UART_Receive_IT(&huart1,(uint8_t*) &RxData,10);
}
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if(huart->Instance == USART1)
{
HAL_UART_Receive_IT(&huart1,(uint8_t*) &RxData,10);
}
There is no problem up to here but when i getting RxData 0. index , it gives EA . Of course it should be give EA. When the adc data change all the ranking is changing. RxData[0] gives meaningless data. adc value is jumping over the all RxData array.
data locations must always be in the same index. How Can I get these data in stability for ex.
RxData[0]=EA
.
.
RxData[4]= should give adc value. so on.
..
Edit: I tried other mode of UART, DMA (in circular mode) and direct mode were used. I cant receive even 1 byte with DMA .
In your example code, you have an extra & that needs to be removed from both the transmit and receive HAL method calls. Example:
HAL_UART_Transmit_IT(&huart1,(uint8_t*) &TxData1,10);
HAL_UART_Transmit_IT(&huart1,(uint8_t*) TxData1,10);
To avoid this type of error in the future, recommend not using the cast and try something like the following:
uint8_t TxData1[10];
...
HAL_UART_Transmit_IT(&huart1, TxData1, sizeof(TxData1);

Connecting multiple slaves with PcDuino SPI bus

I am currently working on a 3D-printer like project where I have to control 3 stepper drivers using SPI from a PcDuino. There a very few examples and only a bad documentation out there describing what I am looking for. It seems the preinstalled API does not support multiple slaves, but if I am understanding it correctly I just have to add more CS lines and control them my self?
Is there anything else to take care of and how long do I need to hold the CS low while sending or receiving data?
(Well I guess receiving is no problem as it is on another line anyway)
Turned out to be quiet easy:
Just have to select, transfer and deselect.
No sleep or waiting needed.
Select and deselect have to be done using the pin devices api,
so you can use as many slaves as you have free pins.
Example implementation:
void GPIOpin::set(FILE* fd, size_t value) {
char buffer[4];
memset(buffer, 0, 4);
sprintf(buffer, "%d", value);
fseek(fd, 0, SEEK_SET);
fwrite(buffer, 1, 4, fd);
fflush(fd);
}
bool SPI::transfer(size_t slaveIndex, uint8_t* buffer, uint64_t size) const {
if(!handle) return false;
struct spi_ioc_transfer transfer;
memset(&transfer, 0, sizeof(transfer));
transfer.len = 1;
for(size_t i = 0; i < size; ++i) {
slaveCS[slaveIndex].setValue(0);
transfer.tx_buf = transfer.rx_buf = (uint64_t)&buffer[i];
if(ioctl(handle, SPI_IOC_MESSAGE(1), &transfer) != transfer.len)
return false;
slaveCS[slaveIndex].setValue(1);
}
return true;
}
Complete code:
https://github.com/Lichtso/PrismCNC/tree/master/backend
Only difficulty: The master has to deselect and reselect the slave for each byte transferred. (but this could be a issue of the slave chips, not sure, just tested 3 different devices including an Arduino)