2013-03-21 11:21 AM
I am using an STM32F4, and I'm having difficulty getting SPI to transmit using DMA. If I manually write to the SPI data register, I see the appropriate activity on the logic analyzer, but if I use DMA to initiate the transaction, I see nothing.
I want to transmit on SPI2, so according to the reference manual, I am using DMA 1 Stream 4, Channel 0. Setting a breakpoint in DMA_GetCmdStatus shows that the CR bit never goes high indicating a problem with the DMA initialization. I've enabled the DMA clock and initialized all the parameters I could think of, but it does not work. I've compared my initialization to other examples and I can't spot any glaring errors. Am I missing something in initialization?// Includes
#include ''stm32f4xx.h''
// SPI2 Interface pins
#define SPI2_SCK_PIN GPIO_Pin_13
#define SPI2_SCK_SOURCE GPIO_PinSource13
#define SPI2_SCK_GPIO_PORT GPIOB
#define SPI2_SCK_GPIO_CLK RCC_AHB1Periph_GPIOB
#define SPI2_MISO_PIN GPIO_Pin_14
#define SPI2_MISO_SOURCE GPIO_PinSource14
#define SPI2_MISO_GPIO_PORT GPIOB
#define SPI2_MISO_GPIO_CLK RCC_AHB1Periph_GPIOB
#define SPI2_MOSI_PIN GPIO_Pin_15
#define SPI2_MOSI_SOURCE GPIO_PinSource15
#define SPI2_MOSI_GPIO_PORT GPIOB
#define SPI2_MOSI_GPIO_CLK RCC_AHB1Periph_GPIOB
#define SPI_BUFFER_SIZE 4
// Private functions
void
delay(uint32_t delayTicks)
{
while
( delayTicks-- != 0 );
}
void
Spi2Init(uint8_t* txBuffer)
{
SPI_InitTypeDef SPI_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
// Enable the SPI clocks
RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);
RCC_AHB1PeriphClockCmd(SPI2_SCK_GPIO_CLK, ENABLE);
RCC_AHB1PeriphClockCmd(SPI2_MISO_GPIO_CLK, ENABLE);
RCC_AHB1PeriphClockCmd(SPI2_MOSI_GPIO_CLK, ENABLE);
// Connect SPI pins to alternate functions
GPIO_PinAFConfig(SPI2_SCK_GPIO_PORT, SPI2_SCK_SOURCE, GPIO_AF_SPI2);
GPIO_PinAFConfig(SPI2_MISO_GPIO_PORT, SPI2_MISO_SOURCE, GPIO_AF_SPI2);
GPIO_PinAFConfig(SPI2_MOSI_GPIO_PORT, SPI2_MOSI_SOURCE, GPIO_AF_SPI2);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN;
// SPI SCK pin configuration
GPIO_InitStructure.GPIO_Pin = SPI2_SCK_PIN;
GPIO_Init(SPI2_SCK_GPIO_PORT, &GPIO_InitStructure);
// SPI MISO pin configuration
GPIO_InitStructure.GPIO_Pin = SPI2_MISO_PIN;
GPIO_Init(SPI2_MISO_GPIO_PORT, &GPIO_InitStructure);
// SPI MOSI pin configuration
GPIO_InitStructure.GPIO_Pin = SPI2_MOSI_PIN;
GPIO_Init(SPI2_MOSI_GPIO_PORT, &GPIO_InitStructure);
// SPI configuration
SPI_I2S_DeInit(SPI2);
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_8;
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
SPI_InitStructure.SPI_CRCPolynomial = 7;
SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
SPI_Init(SPI2, &SPI_InitStructure);
// Configure DMA for transmit
DMA_InitTypeDef DMA_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE);
DMA_DeInit(DMA1_Stream4);
DMA_StructInit(&DMA_InitStructure);
DMA_InitStructure.DMA_Channel = DMA_Channel_0;
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t) (&SPI2->DR);
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)txBuffer;
DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;
DMA_InitStructure.DMA_BufferSize = SPI_BUFFER_SIZE;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
DMA_Init(DMA1_Stream4, &DMA_InitStructure);
DMA_ITConfig(DMA1_Stream4, DMA_IT_TC, ENABLE);
// Configure DMA1 Stream4 interrupt
NVIC_InitStructure.NVIC_IRQChannel = DMA1_Stream4_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 6;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
// Enable SPI2
SPI_Cmd(SPI2, ENABLE);
// Enable DMA request
SPI_I2S_DMACmd(SPI2, SPI_I2S_DMAReq_Tx, ENABLE);
}
uint8_t Spi2SendByte(uint8_t byte)
{
// Loop while DR register in not empty
while
(SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET);
// Send byte through the SPI2 peripheral
SPI_I2S_SendData(SPI2, byte);
// Wait to receive a byte
while
(SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) == RESET);
// Return the byte read from the SPI bus
return
SPI_I2S_ReceiveData(SPI2);
}
int
main(
void
)
{
uint8_t i = 0;
static
uint8_t dataToTransmit[SPI_BUFFER_SIZE];
for
(i = 0; i < SPI_BUFFER_SIZE; i++)
{
dataToTransmit[i] = i;
}
// Initialize the SPI
Spi2Init(dataToTransmit);
while
(1)
{
//Spi2SendByte(i++);
DMA_Cmd(DMA1_Stream4, ENABLE);
DMA_GetCmdStatus(DMA1_Stream4);
delay(200000);
}
}
2014-02-07 02:12 PM
None of the manuals I've looked at suggest PD3 is a valid exit point for SPI2_SCK, pick an appropriate pin.
2014-02-09 07:56 AM
http://www.st.com/web/en/resource/technical/document/datasheet/DM00071990.pdf
STM32F427 Plus, as I said, I can manually send data via the SPI, and I see SCK on this pin.2014-02-09 10:39 AM
Fair enough, on the 407 it does not, on the other hand the code I'd posted to the other thread does generate an SPI clock via DMA. Might port that to the F429 on Monday when I have a scope to hand.
2014-02-09 11:22 AM
I just found a Discovery F4, so I'll try porting this to the '407 and ensure it works. Thanks.
2014-02-10 04:29 AM
EDIT: I was able to get this code working on both the '407 and '427. Now to try to figure out what the difference between this code and mine is...
2014-02-10 07:28 AM
Had the SPI2 clock working on the STM32F429I-DISCO via PD3
[DEAD LINK /public/STe2ecommunities/mcu/Lists/cortex_mx_stm32/Flat.aspx?RootFolder=/public/STe2ecommunities/mcu/Lists/cortex_mx_stm32/SPI%20Clock%20via%20DMA&FolderCTID=0x01200200770978C69A1141439FE559EB459D7580009C4E14902C3CDE46A77F0FFD06506F5B&TopicsView=https://my.st.com/public/STe2ecommunities/mcu/Lists/cortex_mx_stm32/AllItems.aspx¤tviews=80]https://my.st.com/public/STe2ecommunities/mcu/Lists/cortex_mx_stm32/Flat.aspx?RootFolder=%2fpublic%2fSTe2ecommunities%2fmcu%2fLists%2fcortex_mx_stm32%2fSPI%20Clock%20via%20DMA&FolderCTID=0x01200200770978C69A1141439FE559EB459D7580009C4E14902C3CDE46A77F0FFD06506F5B&TopicsView=https%3A%2F%2Fmy.st.com%2Fpublic%2FSTe2ecommunities%2Fmcu%2FLists%2Fcortex_mx_stm32%2FAllItems.aspx¤tviews=802014-02-10 10:05 AM
Clive,
Thanks for the help; figured it out. As I assumed, it was a stupid error: I put the DMA stream/ch mapping into a table in my comments, and kept referring to it when double and triple checking my code. Turns out I copied the wrong table out of the reference manual. It's working now.