arm - 使用 DMA 问题 STM32F0 LL 驱动程序通过 SPI 传输数据
问题描述
我目前正在开发一个项目,将应用程序的数据从 STM32F030c8 芯片发送到树莓派,问题是当我启用 spi 以使用 DMA 并尝试传输时,数据似乎没有发送。这是我目前所做的工作,STM 充当 SLAVE 设备,并在为 DMA 通道调用 IRQ 处理程序时尝试传输。
IRQ 处理程序
void DMA1_Channel4_5_IRQHandler(void)
{
/* USER CODE BEGIN DMA1_Channel4_5_IRQn 0 */
/* USER CODE END DMA1_Channel4_5_IRQn 0 */
LL_GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = LL_GPIO_PIN_8;
GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_HIGH;
GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
GPIO_InitStruct.Pull = LL_GPIO_PULL_UP;
GPIO_InitStruct.Alternate = LL_GPIO_AF_0;
LL_GPIO_Init(GPIOC, &GPIO_InitStruct);
prexfer();
/* USER CODE BEGIN DMA1_Channel4_5_IRQn 1 */
/* USER CODE END DMA1_Channel4_5_IRQn 1 */
}
RX + TX 缓冲器
struct _jd_frame_t {
uint8_t data[JD_SERIAL_PAYLOAD_SIZE + 4];
} __attribute__((__packed__, aligned(4)));
typedef struct _jd_frame_t jd_frame_t;
jd_frame_t tempSend, tempRecv;
程序开始将虚拟数据放入 tempSend,设置 SPI+DMA RX
/* USER CODE END 2 */
tempSend.data[0] = 100;
/* Infinite loop */
/* USER CODE BEGIN WHILE */
setupReceive(&tempRecv, sizeof(tempRecv));
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
// setup transfer
}
开始接收数据的 Rx 设置方法
void setupReceive(const void *receive, uint32_t numbytes){
/* Reset the threshold bit */
CLEAR_BIT(SPI2->CR2, SPI_CR2_LDMATX | SPI_CR2_LDMARX);
// Reception setup
LL_DMA_ConfigAddresses(DMA1, LL_DMA_CHANNEL_4, (uint32_t) & (SPI2->DR), (uint32_t) receive,
LL_DMA_DIRECTION_PERIPH_TO_MEMORY);
LL_DMA_SetDataLength(DMA1, LL_DMA_CHANNEL_4, numbytes);
// Enable SPI
LL_SPI_EnableDMAReq_RX(SPI2);
LL_SPI_Enable(SPI2);
LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_4);
}
SPI + DMA 传输方式
void prexfer(){
xfer(&tempSend, &tempRecv, sizeof(tempSend));
}
void xfer(const void *send, const void *receive, uint32_t numbytes){
/* Reset the threshold bit */
CLEAR_BIT(SPI2->CR2, SPI_CR2_LDMATX | SPI_CR2_LDMARX);
// Reception setup
LL_DMA_ConfigAddresses(DMA1, LL_DMA_CHANNEL_4, (uint32_t) & (SPI2->DR), (uint32_t) receive,
LL_DMA_DIRECTION_PERIPH_TO_MEMORY);
LL_DMA_SetDataLength(DMA1, LL_DMA_CHANNEL_4, numbytes);
// Transfer setup
LL_DMA_ConfigAddresses(DMA1, LL_DMA_CHANNEL_5, (uint32_t) send, (uint32_t) & (SPI2->DR),
LL_DMA_DIRECTION_MEMORY_TO_PERIPH);
LL_DMA_SetDataLength(DMA1, LL_DMA_CHANNEL_5, numbytes);
// Enable SPI
LL_SPI_EnableDMAReq_RX(SPI2);
LL_SPI_EnableDMAReq_TX(SPI2);
LL_SPI_Enable(SPI2);
LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_4);
LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_5);
}
DMA + SPI 设置
static void MX_SPI2_Init(void)
{
LL_SPI_InitTypeDef SPI_InitStruct = {0};
LL_GPIO_InitTypeDef GPIO_InitStruct = {0};
/* Peripheral clock enable */
LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_SPI2);
LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_GPIOB);
LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_GPIOC);
/**SPI2 GPIO Configuration
PB12 ------> SPI2_NSS
PB13 ------> SPI2_SCK
PB14 ------> SPI2_MISO
PB15 ------> SPI2_MOSI
*/
GPIO_InitStruct.Pin = LL_GPIO_PIN_12 | LL_GPIO_PIN_13 | LL_GPIO_PIN_14 | LL_GPIO_PIN_15;
GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_HIGH;
GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
GPIO_InitStruct.Alternate = LL_GPIO_AF_0;
LL_GPIO_Init(GPIOB, &GPIO_InitStruct);
/* SPI2 DMA Init */
/* SPI2_RX Init */
LL_DMA_SetDataTransferDirection(DMA1, LL_DMA_CHANNEL_4, LL_DMA_DIRECTION_PERIPH_TO_MEMORY);
LL_DMA_SetChannelPriorityLevel(DMA1, LL_DMA_CHANNEL_4, LL_DMA_PRIORITY_LOW);
LL_DMA_SetMode(DMA1, LL_DMA_CHANNEL_4, LL_DMA_MODE_NORMAL);
LL_DMA_SetPeriphIncMode(DMA1, LL_DMA_CHANNEL_4, LL_DMA_PERIPH_NOINCREMENT);
LL_DMA_SetMemoryIncMode(DMA1, LL_DMA_CHANNEL_4, LL_DMA_MEMORY_INCREMENT);
LL_DMA_SetPeriphSize(DMA1, LL_DMA_CHANNEL_4, LL_DMA_PDATAALIGN_BYTE);
LL_DMA_SetMemorySize(DMA1, LL_DMA_CHANNEL_4, LL_DMA_MDATAALIGN_BYTE);
/* SPI2_TX Init */
LL_DMA_SetDataTransferDirection(DMA1, LL_DMA_CHANNEL_5, LL_DMA_DIRECTION_MEMORY_TO_PERIPH);
LL_DMA_SetChannelPriorityLevel(DMA1, LL_DMA_CHANNEL_5, LL_DMA_PRIORITY_LOW);
LL_DMA_SetMode(DMA1, LL_DMA_CHANNEL_5, LL_DMA_MODE_NORMAL);
LL_DMA_SetPeriphIncMode(DMA1, LL_DMA_CHANNEL_5, LL_DMA_PERIPH_NOINCREMENT);
LL_DMA_SetMemoryIncMode(DMA1, LL_DMA_CHANNEL_5, LL_DMA_MEMORY_INCREMENT);
LL_DMA_SetPeriphSize(DMA1, LL_DMA_CHANNEL_5, LL_DMA_PDATAALIGN_BYTE);
LL_DMA_SetMemorySize(DMA1, LL_DMA_CHANNEL_5, LL_DMA_MDATAALIGN_BYTE);
/* USER CODE BEGIN SPI2_Init 1 */
/* USER CODE END SPI2_Init 1 */
/* SPI2 parameter configuration*/
SPI_InitStruct.TransferDirection = LL_SPI_FULL_DUPLEX;
SPI_InitStruct.Mode = LL_SPI_MODE_SLAVE;
SPI_InitStruct.DataWidth = LL_SPI_DATAWIDTH_4BIT;
SPI_InitStruct.ClockPolarity = LL_SPI_POLARITY_LOW;
SPI_InitStruct.ClockPhase = LL_SPI_PHASE_1EDGE;
SPI_InitStruct.NSS = LL_SPI_NSS_HARD_INPUT;
SPI_InitStruct.BitOrder = LL_SPI_MSB_FIRST;
SPI_InitStruct.CRCCalculation = LL_SPI_CRCCALCULATION_DISABLE;
SPI_InitStruct.CRCPoly = 7;
LL_SPI_Init(SPI2, &SPI_InitStruct);
LL_SPI_SetStandard(SPI2, LL_SPI_PROTOCOL_MOTOROLA);
LL_SPI_DisableNSSPulseMgt(SPI2);
/* USER CODE BEGIN SPI2_Init 2 */
/* USER CODE END SPI2_Init 2 */
}
/**
* Enable DMA controller clock
*/
static void MX_DMA_Init(void)
{
/* Init with LL driver */
/* DMA controller clock enable */
LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_DMA1);
/* DMA interrupt init */
/* DMA1_Channel4_5_IRQn interrupt configuration */
NVIC_SetPriority(DMA1_Channel4_5_IRQn, 1);
NVIC_EnableIRQ(DMA1_Channel4_5_IRQn);
}
所以代码应该如何工作的是,当我设置 RX 并从 RPi 接收数据时,它应该调用 DMA1 IRQ 处理程序来传输数据,但它永远不会被调用,非常感谢任何帮助!
解决方案
推荐阅读
- bluetooth - BlueZ:接口“org.bluez.Network1”上带有签名“s”的方法“Connect”不存在
- c# - 统一容器解决协方差
- javascript - 将 HighCharts 的 svg 输出 POST 到内部服务器
- react-native - React Navigation v3 Modal 不适用于 createBottomTabNavigator
- python - Pandas: count gaps for specific values
- python - Django获取PointField的坐标值
- jquery - 将 div 内部的滚动匹配到另一个外部 div
- java - 重用 bean 的 XML 片段
- c# - 将可执行文件包含到 UWP 最终包中
- c# - 在 GetLogger 上调用特定记录器的自定义 PatternLayout
();