I'm trying to communicate betwenn two NucleoF303K8 boards via SPI. One board is Master and is controlled by UART. It can send via SPI 3 kinds of messages:
{0x01 0x00 0x00 0x00}
that means 'read value'{0x81 0x00 0x00 0x00}
that means 'set value = 0'{0x81 0x01 0x00 0x00}
that means 'set value = 1'
The other board is Slave. It sets (and gets) LED pin value depending on command.
Slave algorythm is as follows:
when
NSS_Pin
becomes low,EXTI_Callback
is called, and starts recievemnt of 1 byteAfter First byte is recieved, I guess if it is readout command or writein
if it is readback I use
SPI_DMA
to transmit value if it writein I useSPI DMA
to receive valuewhen
NSS_Pin
gets to high level again, slave processes message if it waswriteIn
or just waits for another command if it wasreadout
Here is the code:
extern DMA_HandleTypeDef hdma_spi1_tx;
extern DMA_HandleTypeDef hdma_spi1_rx;
extern SPI_HandleTypeDef hspi1;
uint8_t txb[16] = {0x01,0xAA,0xBB};
uint8_t rxb[16] = {};
uint8_t code = 0;
uint8_t op = 0; // 0: idle, 1: readout, 2: writein
void readOut(){
op = 1;
HAL_SPI_Transmit_DMA(&hspi1, txb,3);
}
void receiveWriteIn(){
op = 2;
HAL_SPI_Receive_DMA(&hspi1, rxb, 3);
}
void processWriteIn(){
HAL_GPIO_WritePin(LD3_GPIO_Port, LD3_Pin, (GPIO_PinState)rxb[0]);
}
void SystemLoad(){
HAL_GPIO_WritePin(LD3_GPIO_Port,LD3_Pin,GPIO_PIN_SET);
while(1){
}
}
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin){
HAL_SPI_DMAStop(&hspi1);
if(GPIO_Pin == NSS_Pin){
if(HAL_GPIO_ReadPin(NSS_GPIO_Port, NSS_Pin) == GPIO_PIN_RESET){
op = 0;
HAL_SPI_Receive_DMA(&hspi1,&code,1);
}else{
if(op == 2){
processWriteIn();
}
op = 0;
code = 0;
}
}
}
inline void mainCbk(SPI_HandleTypeDef *hspi){
HAL_SPI_DMAStop(hspi);
if(hspi == &hspi1){
if(op == 0){
if(code & 0x80){
receiveWriteIn();
}else{
readOut();
}
}
}
}
void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi){
mainCbk(hspi);
}
void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi){
mainCbk(hspi);
}
void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef *hspi){
mainCbk(hspi);
}
Slave settings in CubeMX are:
1 GPIO output (LED) and one EXTI
SPI1
withDMARX
(Priority high) andDMATX
(priority Very High) andNVIC
enabled for both DMA channels and SPI1 global interruptNVIC priority, Debug, SysTick, etc. with highest priority (0), EXTI and SPI1 global interrupt with lower priority (1)
HCLK is 64 MHz, PCLK1 is 32 MHz, PCLK2 is 64 MHz
SPI speed from Master device is 250 KBit/s
For some reason I have two main problems:
writeIn
data migrates inrxbuffer
cyclicaly. That0x01
in 'set value = 1' appears inrxb[0]
then inrxb[1]
,rxb[2]
and from beggining on each SPI message.readout data, that slaves transmitts also acts strange: on first 2 messages I recieve on master device (and see with logic analyzer on the line) proper values:
{0x00 0x01 0xAA 0xBB}
but then something changes andit becomes
{0xBB 0x01 0xAA 0xBB}
or
{0xBB 0x00 0x01 0xBB}
or
{0xBB 0x81 0xAA 0xBB}
and if I after readout try to writein it becomes like
{0xBB 0xBB 0xBB 0xBB}
though rxb
that is in HAL_SPI_Receive_DMA(&hspi1, rxb, 3);
is filled with 0
I've looked into SPI1.DR register, but it is 0, so I don't know what to think. I've tried to DMAStop on message TX and RX callbacks, also I've tried SPI_Abort.
I've mixed priority levels in different ways:
all equal
EXTI > SPI > DMARX > DMATX (and TX > RX)
DMATX > DMARX > EXTI = SPI
DMATX > DMARX > EXTI > SPI
DMATX > DMARX > SPI > EXTI
Also I've tried to use HAL_SPI_Transmit_IT
, but had the same result even if DMA was disabled at all.
Theoretically it have to work correct as SPI buffer is filled before the next byte si going to be transmitted, but it seems to act very strange.
What is the proper way to configure my device? Or maybe MCU cannot be controlled in such a way, as it has to use software core, to process messages, and there is proper way of doing this?