Я уже задавал этот вопрос на форуме mbed, но ответа не получил.
Введение
У меня две платы Nucleo L432kc, яхотите, чтобы они общались с протоколом SPI, используя DMA.
В следующей схеме вы можете увидеть фактическую настройку оборудования:
Что работает
Если я отправляю данные от ведущего к подчиненному, я получаю их правильно, а когда ведущее устройство не передает, ведомое устройство ничего не получает.
Код мастера
#include <mbed.h>
uint8_t dma_buffer_tx[4];
uint8_t dma_buffer_rx[4];
uint8_t buff[4];
uint32_t receive_buff_length = 4;
unsigned int c = 0;
Serial pc(USBTX,USBRX,921600);
DigitalOut led(LED3);
SPI_HandleTypeDef hspi1;
DMA_HandleTypeDef hdma_spi1_rx;
DMA_HandleTypeDef hdma_spi1_tx;
void Error_Handler(){
led.write(1);
while(1){}
}
static void HAL_GPIO_Init(void){
GPIO_InitTypeDef GPIO_InitStruct = {0};
if(hspi1.Instance==SPI1)
{
__HAL_RCC_GPIOA_CLK_ENABLE();
/**SPI1 GPIO Configuration
PA1 ------> SPI1_SCK
PA11 ------> SPI1_MISO
PA12 ------> SPI1_MOSI
*/
GPIO_InitStruct.Pin = GPIO_PIN_1|GPIO_PIN_11|GPIO_PIN_12;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF5_SPI1;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}
else
Error_Handler();
}
static void SPI1_Init(void)
{
__HAL_RCC_SPI1_CLK_ENABLE();
/* SPI1 parameter configuration*/
hspi1.Instance = SPI1;
hspi1.Init.Mode = SPI_MODE_MASTER;
hspi1.Init.Direction = SPI_DIRECTION_2LINES;
hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
hspi1.Init.NSS = SPI_NSS_SOFT;
hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;
hspi1.Init.CRCPolynomial = 7;
hspi1.Init.CRCLength = SPI_CRC_LENGTH_DATASIZE;
hspi1.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;
if (HAL_SPI_Init(&hspi1) != HAL_OK)
{
Error_Handler();
}
/* SPI1 interrupt Init */
HAL_NVIC_SetPriority(SPI1_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(SPI1_IRQn);
}
static void DMA_Init(void)
{
/* DMA controller clock enable */
__HAL_RCC_DMA1_CLK_ENABLE();
/* SPI1 DMA Init */
/* SPI1_RX Init */
hdma_spi1_rx.Instance = DMA1_Channel2;
hdma_spi1_rx.Init.Request = DMA_REQUEST_1;
hdma_spi1_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_spi1_rx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_spi1_rx.Init.MemInc = DMA_MINC_ENABLE;
hdma_spi1_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_spi1_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_spi1_rx.Init.Mode = DMA_NORMAL;
hdma_spi1_rx.Init.Priority = DMA_PRIORITY_LOW;
if (HAL_DMA_Init(&hdma_spi1_rx) != HAL_OK)
{
Error_Handler();
}
__HAL_LINKDMA(&hspi1,hdmarx,hdma_spi1_rx);
/* DMA interrupt init */
/* DMA1_Channel2_IRQn interrupt configuration */
HAL_NVIC_SetPriority(DMA1_Channel2_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(DMA1_Channel2_IRQn);
/* SPI1 DMA Init */
/* SPI1_TX Init */
hdma_spi1_tx.Instance = DMA1_Channel3;
hdma_spi1_tx.Init.Request = DMA_REQUEST_1;
hdma_spi1_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
hdma_spi1_tx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_spi1_tx.Init.MemInc = DMA_MINC_ENABLE;
hdma_spi1_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_spi1_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_spi1_tx.Init.Mode = DMA_NORMAL;
hdma_spi1_tx.Init.Priority = DMA_PRIORITY_LOW;
if (HAL_DMA_Init(&hdma_spi1_tx) != HAL_OK)
{
Error_Handler();
}
__HAL_LINKDMA(&hspi1,hdmatx,hdma_spi1_tx);
/* DMA interrupt init */
/* DMA1_Channel3_IRQn interrupt configuration */
HAL_NVIC_SetPriority(DMA1_Channel3_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(DMA1_Channel3_IRQn);
}
extern "C"{
void DMA1_Channel3_IRQHandler(void)
{
HAL_NVIC_ClearPendingIRQ(DMA1_Channel3_IRQn);
HAL_DMA_IRQHandler(&hdma_spi1_tx);
}
void DMA1_Channel2_IRQHandler(void)
{
HAL_NVIC_ClearPendingIRQ(DMA1_Channel2_IRQn);
HAL_DMA_IRQHandler(&hdma_spi1_rx);
}
void SPI1_IRQHandler(void)
{
HAL_SPI_IRQHandler(&hspi1);
}
}
void HAL_SPI_RxHalfCpltCallback(SPI_HandleTypeDef *hspi1){
for(int i = 0; i < receive_buff_length/2; i++){
buff[i] = dma_buffer_rx[i];
}
}
void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef *hspi1){
for(int i = receive_buff_length/2; i < receive_buff_length; i++){
buff[i] = dma_buffer_rx[i];
}
printf("%u\n",*(unsigned int *)buff); // to understan when I am actually receiving data
memset(dma_buffer_rx,0,sizeof(dma_buffer_rx));
}
void HAL_SPI_TxHalfCpltCallback(SPI_HandleTypeDef *hspi1){
c += 5;
dma_buffer_tx[0] = c & 0xFF;
dma_buffer_tx[1] = (c >> 8) & 0xFF;
}
void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi1){
dma_buffer_tx[2] = (c >> 16) & 0xFF;
dma_buffer_tx[3] = (c >> 24) & 0xFF;
}
int main(void)
{
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* SPI INIT */
SPI1_Init();
/* GPIO USART2 INIT */
HAL_GPIO_Init();
/* DMA INIT */
DMA_Init();
c = 1000;
dma_buffer_rx[0] = c & 0xFF;
dma_buffer_rx[1] = (c >> 8) & 0xFF;
dma_buffer_rx[2] = (c >> 16) & 0xFF;
dma_buffer_rx[3] = (c >> 24) & 0xFF;
while(true){
HAL_SPI_Transmit_DMA(&hspi1,dma_buffer_rx,receive_buff_length);
wait(0.001);
}
}
Код ведомого
#include <mbed.h>
uint8_t dma_buffer_tx[4];
uint8_t dma_buffer_rx[4];
uint8_t buff[4];
uint32_t receive_buff_length = 4;
unsigned int c = 0;
Serial pc(USBTX,USBRX,921600);
DigitalOut led(LED3);
SPI_HandleTypeDef hspi1;
DMA_HandleTypeDef hdma_spi1_rx;
DMA_HandleTypeDef hdma_spi1_tx;
void Error_Handler(){
led.write(1);
while(1){}
}
static void HAL_GPIO_Init(void){
GPIO_InitTypeDef GPIO_InitStruct = {0};
if(hspi1.Instance==SPI1)
{
__HAL_RCC_GPIOA_CLK_ENABLE();
/**SPI1 GPIO Configuration
PA1 ------> SPI1_SCK
PA11 ------> SPI1_MISO
PA12 ------> SPI1_MOSI
*/
GPIO_InitStruct.Pin = GPIO_PIN_1|GPIO_PIN_11|GPIO_PIN_12;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF5_SPI1;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}
else
Error_Handler();
}
static void SPI1_Init(void)
{
__HAL_RCC_SPI1_CLK_ENABLE();
/* SPI1 parameter configuration*/
hspi1.Instance = SPI1;
hspi1.Init.Mode = SPI_MODE_SLAVE;
hspi1.Init.Direction = SPI_DIRECTION_2LINES;
hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
hspi1.Init.NSS = SPI_NSS_SOFT;
hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;
hspi1.Init.CRCPolynomial = 7;
hspi1.Init.CRCLength = SPI_CRC_LENGTH_DATASIZE;
hspi1.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;
if (HAL_SPI_Init(&hspi1) != HAL_OK)
{
Error_Handler();
}
/* SPI1 interrupt Init */
HAL_NVIC_SetPriority(SPI1_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(SPI1_IRQn);
}
static void DMA_Init(void)
{
/* DMA controller clock enable */
__HAL_RCC_DMA1_CLK_ENABLE();
/* SPI1 DMA Init */
/* SPI1_RX Init */
hdma_spi1_rx.Instance = DMA1_Channel2;
hdma_spi1_rx.Init.Request = DMA_REQUEST_1;
hdma_spi1_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_spi1_rx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_spi1_rx.Init.MemInc = DMA_MINC_ENABLE;
hdma_spi1_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_spi1_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_spi1_rx.Init.Mode = DMA_NORMAL;
hdma_spi1_rx.Init.Priority = DMA_PRIORITY_LOW;
if (HAL_DMA_Init(&hdma_spi1_rx) != HAL_OK)
{
Error_Handler();
}
__HAL_LINKDMA(&hspi1,hdmarx,hdma_spi1_rx);
/* DMA interrupt init */
/* DMA1_Channel2_IRQn interrupt configuration */
HAL_NVIC_SetPriority(DMA1_Channel2_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(DMA1_Channel2_IRQn);
/* SPI1 DMA Init */
/* SPI1_TX Init */
hdma_spi1_tx.Instance = DMA1_Channel3;
hdma_spi1_tx.Init.Request = DMA_REQUEST_1;
hdma_spi1_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
hdma_spi1_tx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_spi1_tx.Init.MemInc = DMA_MINC_ENABLE;
hdma_spi1_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_spi1_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_spi1_tx.Init.Mode = DMA_NORMAL;
hdma_spi1_tx.Init.Priority = DMA_PRIORITY_LOW;
if (HAL_DMA_Init(&hdma_spi1_tx) != HAL_OK)
{
Error_Handler();
}
__HAL_LINKDMA(&hspi1,hdmatx,hdma_spi1_tx);
/* DMA interrupt init */
/* DMA1_Channel3_IRQn interrupt configuration */
HAL_NVIC_SetPriority(DMA1_Channel3_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(DMA1_Channel3_IRQn);
}
extern "C"{
void DMA1_Channel3_IRQHandler(void)
{
HAL_NVIC_ClearPendingIRQ(DMA1_Channel3_IRQn);
HAL_DMA_IRQHandler(&hdma_spi1_tx);
}
void DMA1_Channel2_IRQHandler(void)
{
HAL_NVIC_ClearPendingIRQ(DMA1_Channel2_IRQn);
HAL_DMA_IRQHandler(&hdma_spi1_rx);
}
void SPI1_IRQHandler(void)
{
HAL_SPI_IRQHandler(&hspi1);
}
}
void HAL_SPI_RxHalfCpltCallback(SPI_HandleTypeDef *hspi1){
for(int i = 0; i < receive_buff_length/2; i++){
buff[i] = dma_buffer_rx[i];
}
}
void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef *hspi1){
for(int i = receive_buff_length/2; i < receive_buff_length; i++){
buff[i] = dma_buffer_rx[i];
}
printf("%u\n",*(unsigned int *)buff); // to understan when I am actually receiving data
memset(dma_buffer_rx,0,sizeof(dma_buffer_rx));
}
void HAL_SPI_TxHalfCpltCallback(SPI_HandleTypeDef *hspi1){
c += 5;
dma_buffer_tx[0] = c & 0xFF;
dma_buffer_tx[1] = (c >> 8) & 0xFF;
}
void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi1){
dma_buffer_tx[2] = (c >> 16) & 0xFF;
dma_buffer_tx[3] = (c >> 24) & 0xFF;
}
int main(void)
{
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* SPI INIT */
SPI1_Init();
/* GPIO USART2 INIT */
HAL_GPIO_Init();
/* DMA INIT */
DMA_Init();
c = 1000;
dma_buffer_rx[0] = c & 0xFF;
dma_buffer_rx[1] = (c >> 8) & 0xFF;
dma_buffer_rx[2] = (c >> 16) & 0xFF;
dma_buffer_rx[3] = (c >> 24) & 0xFF;
while(true){
HAL_SPI_Receive_DMA(&hspi1,dma_buffer_rx,receive_buff_length);
}
}
Что не работает
Если я изменяю роль в сообщении, поэтому я отправляю данные из salve введущий меняет следующие строки
[...]
HAL_SPI_Transmit_DMA(&hspi1,dma_buffer_rx,receive_buff_length);
wait(0.001);
[...]
на:
[...]
HAL_SPI_Receive_DMA(&hspi1,dma_buffer_rx,receive_buff_length);
[...]
Даже если ведомый не включен, ведущий непрерывно получает прерывания и вызывает HAL_SPI_RxCpltCallback
.Если мы включаем подчиненное устройство, мастер печатает случайные числа.
То, что я уже попробовал без успеха
- Я проверил мастер-код на плате Nucleo F446.
- Я установил понижающие и подтягивающие резисторы на выводе MISO.
- Я пробовал другой кабель для подключения hw.
- Я пытался использовать напрямуюфункция HAL_SPI_TransmitReceive_DMA, но поведение такое же.на самом деле называется.Я думаю, что один и тот же буфер используется для передачи и приема, но я не знаю, как это доказать.Я также напечатал
hdma_spi1_rx.Instance->CNDTR
и заметил, что значение увеличивается до 4, что на самом деле является количеством байтов, которые мы собираемся получить.