2014-07-20 01:55 PM
Hi guys!
Is there anyone that has some experience in setting up this kind of DMA streaming? I would like to stream 16-bit data to an external DAC, with no sweat for the processor. I've read that timer triggered DMA transfers to SPI are a viable option, and also found some sample code for it. I have configured my TIM1 to run in OC mode, SPI1 relevant pins and the DMA peripheral toDMA2_Stream3 using Channel_6 as is written in the datasheet. When I run my code the output is dead, if I look at the DR register for SPI1 is also 0x0000, so no data is pouring in from the DMA. Does anyone have any suggestions? Should I include some additional code to the main loop, that I am not aware of (I initialize all the peripherals, and in my understanding this should work)? Here is my initialization function, that I use at startup:
void spi1_init(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
DMA_InitTypeDef DMA_InitStructure;
SPI_InitTypeDef SPI_InitStruct;
GPIO_InitTypeDef GPIO_InitStructure;
/*
* GPIO configuration
*/
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
/* Configure pins used by SPI1:
* PA4 = NSS
* PA5 = SCLK
* PA6 = MISO
* PA7 = MOSI */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7 | GPIO_Pin_6 | GPIO_Pin_5 | GPIO_Pin_4;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* Connect SPI1 pins to SPI alternate function */
GPIO_PinAFConfig(GPIOA, GPIO_PinSource4, GPIO_AF_SPI1);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource5, GPIO_AF_SPI1);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource6, GPIO_AF_SPI1);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource7, GPIO_AF_SPI1);
/* Enable the SPI peripheral clock */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);
/* Configure SPI1 in Mode 0:
* CPOL = 0 --> clock is low when idle
* CPHA = 0 --> data is sampled at the first edge
*
* SPI Master mode, 8 bits of data, clock prescalar is 256, MSB is
* transmitted first. */
SPI_InitStruct.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
SPI_InitStruct.SPI_Mode = SPI_Mode_Master;
SPI_InitStruct.SPI_DataSize = SPI_DataSize_8b;
SPI_InitStruct.SPI_CPOL = SPI_CPOL_Low;
SPI_InitStruct.SPI_CPHA = SPI_CPHA_1Edge;
SPI_InitStruct.SPI_NSS = SPI_NSS_Soft | SPI_NSSInternalSoft_Set;
SPI_InitStruct.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;
SPI_InitStruct.SPI_FirstBit = SPI_FirstBit_MSB;
SPI_Init(SPI1, &SPI_InitStruct);
/* Enable SPI */
SPI_Cmd(SPI1, ENABLE);
/*
* TIM1 Configuration
*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
/* Time base configuration */
TIM_TimeBaseStructure.TIM_Period = 150;
TIM_TimeBaseStructure.TIM_Prescaler = (uint16_t)(SystemCoreClock / 40000000) - 1;
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
/* PWM1 Mode configuration: Channel1 */
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = 5;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OC1Init(TIM1, &TIM_OCInitStructure);
TIM_OC1PreloadConfig(TIM1, TIM_OCPreload_Enable);
TIM_SelectOutputTrigger(TIM1, TIM_TRGOSource_Update);
TIM_ARRPreloadConfig(TIM1, ENABLE);
TIM_Cmd(TIM1, ENABLE);
/*
* DMA2 Configuration
*/
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);
DMA_DeInit(DMA2_Stream3);
DMA_StructInit(&DMA_InitStructure);
DMA_InitStructure.DMA_Channel = DMA_Channel_6;
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&SPI1->DR;
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&test_buffer;
DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;
DMA_InitStructure.DMA_BufferSize = TEST_BUFFER_LEN;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
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_ITConfig(DMA2_Stream3, DMA_IT_TC, DISABLE);
DMA_Init(DMA2_Stream3, &DMA_InitStructure);
DMA_Cmd(DMA2_Stream3, ENABLE);
TIM_DMACmd(TIM1, TIM_DMA_Update, ENABLE);
}
Thanks for your suggestions.
BR,
Blaz
2014-07-20 02:48 PM
UPDATE:
I've changed the DMA request source from DMA2_Stream3 to DMA2_Stream5, which should be reserved for the TIM1_UP event. Interestingly enough, I see one stream of data probing the CLK and MOSI lines with my DSO as I start the application, but then it's over. Also no activity on the NSS line, which is strange. Thanks for your input!2014-07-20 04:17 PM
Reading SPIx->DR tells you what's in the receive register, not the transmit one.
In DMA Normal mode it's going to send the stream once and stop.TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
TIM3?
TIM1_UP DMA Stream 5 Channel 6
TIM_SelectOutputTrigger(TIM1, TIM_TRGOSource_Update);
TIM_DMACmd(TIM1, TIM_DMA_Trigger, ENABLE);
or
TIM_DMACmd(TIM1, TIM_DMA_Update, ENABLE);
/* TIM enable counter */
TIM_Cmd(TIM1, ENABLE);
/* Main Output Enable, and Input */
TIM_CtrlPWMOutputs(TIM1, ENABLE);
2014-07-21 01:47 AM
Hi Clive!
Thanks for your prompt answer. TIM3 -> typo, fixed but no change to behaviour I also tried both options you provided: 1.TIM_SelectOutputTrigger(TIM1, TIM_TRGOSource_Update);
TIM_DMACmd(TIM1, TIM_DMA_Trigger, ENABLE);
I get nothing on the output of the SPI1 pins.
2.
TIM_DMACmd(TIM1, TIM_DMA_Update, ENABLE);
/* TIM enable counter */
TIM_Cmd(TIM1, ENABLE);
/* Main Output Enable, and Input */
TIM_CtrlPWMOutputs(TIM1, ENABLE);
I get the same behavior as before (i.e. some data pouring out at reset, and than silence)
Also I attached a picture from the DSO (it should stream 32, 16-bit numbers periodically):
yellow - CLK, purple - MOSI, blue - NSS
Any other suggestions? Could it be that the discovery board pin mappings are the problem (SPI PA pins are already used on discovery for LIS302DL)? Should I be clearing some flags, that I am not aware of?
Thanks again!
2014-07-22 10:45 AM
Hi guys! Does anyone else have some suggestions? I'm pretty stuck...
2014-11-20 11:29 AM
Hi Blaz,
That's exactly what I want to do. Do solve? In that case I'll really appreciate if you can post the full code! I'm really a beginner with STM32 and sharing your files will greatly help; even if I understand very well that coding by yourself is what make you understand how to do. Thanks in advance. Best regards, Franck2014-12-03 07:01 AM
Hi Blaz,
Have you come out? Best regards,