Question
DMA only sending one byte and not whole buffer
Posted on October 21, 2015 at 14:43
STM32f30x
The aim is to trigger the DMA from a timer. The DMA should then send one row of data from my buffer to the SPI. The DMA should then trigger an interrupt which points DMA to the next row in the buffer. It should now wait until it is triggered again from the timer before sending. Currently this all works but for one thing. It only sends 1 byte to the SPI and then waits for the timer trigger before sending the next. On a scope I can see that if I change the timer speed then the inter byte gap coming out of SPI changes.#include ''stm32f30x_dma.h''
#include ''stm32f30x_gpio.h''
#include ''stm32f30x_rcc.h''
#include ''stm32f30x_spi.h''
#include ''stm32f30x_tim.h''
#include ''stm32f30x_misc.h''
#include ''stm32f30x_syscfg.h''
#define X_OFFSET 20
#define ROW 200
#define COL 32
#define START1 24
#define END1 312
uint8_t MemBuf[ROW][COL];
uint8_t RowCount = 0;
GPIO_InitTypeDef GPIO_InitStruct;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
SPI_InitTypeDef SPI_InitStructure;
DMA_InitTypeDef DMA_InitStructure;
//-----------------------------------------------------------------
void Init(void)
{
uint16_t PrescalerValue = 0;
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB, ENABLE);//GPIOB clock enable
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE); //TIM4 clock enable
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);//DMA1 clock enable
RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);//SPI2 clock enable
//------------------
//GPIO Setup - output for MOSI
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_15 ; // we want to configure AF pins on port B
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF; // we want the pins to be alternate functions
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; // this sets the GPIO modules clock speed
GPIO_InitStruct.GPIO_OType = GPIO_OType_PP; // this sets the pin type to push / pull (as opposed to open drain)
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP; // this sets the pullup / pulldown resistors
GPIO_Init(GPIOB, &GPIO_InitStruct);
//------------------
//TIM4 setup
PrescalerValue = (uint16_t) (SystemCoreClock / 2000000) - 1;//Compute the prescaler value
TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);// Time Base configuration
TIM_TimeBaseStructure.TIM_Prescaler = PrescalerValue;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseStructure.TIM_Period = X_OFFSET + 80;
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure);
//setup the output compare
TIM_OCStructInit(&TIM_OCInitStructure);
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Timing;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Disable;
TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Disable;
TIM_OCInitStructure.TIM_Pulse = X_OFFSET;
TIM_OC1Init(TIM4, &TIM_OCInitStructure);
TIM_OC1PreloadConfig(TIM4, TIM_OCPreload_Enable);//??
TIM_ARRPreloadConfig(TIM4, ENABLE); //??
//Master mode - trigger DMA
TIM_SelectOutputTrigger(TIM4, TIM_TRGOSource_OC1Ref);
//------------------
TIM_DMACmd(TIM4,TIM_DMA_CC1, ENABLE ); // Enable TIM1_CC1 DMA Requests
//------------------
//Interrupt setup
//Enable DMA1 channel IRQ Channel
NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
//------------------
//DMA1 setup
//Transfer Data to SPI2 from RAM buffer
//Trigger from TIM4 OC1
DMA_Cmd(DMA1_Channel1, DISABLE);
DMA_DeInit(DMA1_Channel1);//reset DMA1 channe1 to default values;
DMA_StructInit(&DMA_InitStructure);
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;//channel will be used for memory to SPI transfer
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;//setting normal mode (non circular)
DMA_InitStructure.DMA_Priority = DMA_Priority_High;//medium priority
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;//source and destination data size half word=16bit
DMA_InitStructure.DMA_MemoryDataSize = DMA_PeripheralDataSize_Byte;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//automatic memory increment enable.
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;//Location assigned to peripheral register will be destination
DMA_InitStructure.DMA_BufferSize = COL;// / 2;//amount of data to be transfered - divide by 2 because we using 16bit
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&SPI2->DR;//source and destination start addresses
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&MemBuf;
DMA_Init(DMA1_Channel1, &DMA_InitStructure);//send values to DMA registers
DMA_ITConfig(DMA1_Channel1, DMA_IT_TC, ENABLE);// Enable DMA1 Channel Transfer Complete interrupt
//------------------
//SPI setup
SPI_InitStructure.SPI_Direction = SPI_Direction_1Line_Tx;
SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;
SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft ;
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_128;
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
SPI_InitStructure.SPI_CRCPolynomial = 7;
SPI_Init(SPI2, &SPI_InitStructure);
SPI_I2S_DMACmd (SPI2,SPI_I2S_DMAReq_Tx,ENABLE);
//------------------
//Connect output to alternate function - AF2
GPIO_PinAFConfig(GPIOB, GPIO_PinSource15, GPIO_AF_5); //MOSI on SPI2
//------------------
SPI_Cmd(SPI2, ENABLE);
TIM_Cmd(TIM4, ENABLE);
DMA_Cmd(DMA1_Channel1, ENABLE);
}
//-----------------------------------------------------------------
void DMA1_Channel1_IRQHandler(void)
{
if(DMA_GetITStatus(DMA1_IT_TC1))
{
DMA_ClearITPendingBit(DMA1_IT_TC1 | DMA1_IT_GL1);
DMA_Cmd(DMA1_Channel1, DISABLE);
RowCount++;
if(RowCount >= ROW)
{
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)MemBuf;//end of buffer reached - start at beginning
RowCount = 0;
}
else
{
DMA_InitStructure.DMA_MemoryBaseAddr += COL;//move to next row in buffer
}
DMA_Init(DMA1_Channel1, &DMA_InitStructure);//send values to DMA registers
DMA_Cmd(DMA1_Channel1, ENABLE);
}
else
{
DMA_ClearITPendingBit(DMA1_IT_GL1);
}
}
//-----------------------------------------------------------------
int main(void)
{
Init();
for (uint8_t var = 0; var < 20; ++var)
{
MemBuf[0][var] = 0xaa;//put some stuff in one row of the buffer
}
while(1)
{
//put your code here
}
}