2017-07-17 07:25 AM
Hello,
I try to read acceleration values from a LIS3DSHTR using the STM32F091 �C. I use SPI with DMA to read the values but I have trouble with the incoming datas in the RxBuffer.
On my two screenshots you can see the bus communication and the position of the data inside my RxBuffer. The order is totally wrong.
I hope someone can check the source code. I hope you can find a stupid mistake
void SPI_init()
{ SPI_InitTypeDef SPI_InitStructure;// clk
RCC->AHBENR |= RCC_AHBENR_GPIOAEN; RCC->APB2ENR |= RCC_APB2ENR_SPI1EN;// set af mode
GPIOA->MODER = ( GPIOA->MODER & ~(GPIO_MODER_MODER5 | GPIO_MODER_MODER6 | GPIO_MODER_MODER7)); GPIOA->MODER |= ( GPIO_MODER_MODER5_1 | GPIO_MODER_MODER6_1 | GPIO_MODER_MODER7_1);GPIOA->AFR[1] = (GPIOA->AFR[1] &~ (GPIO_AFRL_AFR5)) | (0 << GPIO_AFR_POS5);
GPIOA->AFR[1] = (GPIOA->AFR[1] &~ (GPIO_AFRL_AFR6)) | (0 << GPIO_AFR_POS6); GPIOA->AFR[1] = (GPIOA->AFR[1] &~ (GPIO_AFRL_AFR7)) | (0 << GPIO_AFR_POS7);SPIx_PORT->MODER |= ( GPIO_MODER_MODER4_0);
SPIx_PORT->OTYPER &= ~( GPIO_OTYPER_OT_4); SPIx_PORT->OSPEEDR |= ( GPIO_OSPEEDER_OSPEEDR4); SPIx_PORT->PUPDR &= ~( GPIO_PUPDR_PUPDR4);SPIx_PORT->BSRR = GPIO_BSRR_BS_4; //High - Deselect ACC
/*SPI1-Konfigurieren*/
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; SPI_InitStructure.SPI_Mode = SPI_Mode_Master; SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low; SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge; SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_64; SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; SPI_InitStructure.SPI_CRCPolynomial = 7; SPI_Init(SPIx,&SPI_InitStructure);//Use DMA for SPI
SPI_I2S_DMACmd(SPIx, SPI_I2S_DMAReq_Tx, ENABLE); SPI_I2S_DMACmd(SPIx, SPI_I2S_DMAReq_Rx, ENABLE);SPI_Cmd(SPIx, ENABLE);
//Init DMA
DMA_Config();//Init the buffer with the needed registers of the acc
AccelerationRequest[0] = ACCELEROMETER_OUT_X_L; AccelerationRequest[1] = 0x00; //dummy AccelerationRequest[2] = ACCELEROMETER_OUT_X_H; AccelerationRequest[3] = 0x00; AccelerationRequest[4] = ACCELEROMETER_OUT_Y_L; AccelerationRequest[5] = 0x00; AccelerationRequest[6] = ACCELEROMETER_OUT_Y_H; AccelerationRequest[7] = 0x00; AccelerationRequest[8] = ACCELEROMETER_OUT_Z_L; AccelerationRequest[9] = 0x00; AccelerationRequest[10] = ACCELEROMETER_OUT_Z_H; AccelerationRequest[11] = 0x00;}void DMA_Config()
{ DMA_InitTypeDef DMA_InitStructure; NVIC_InitTypeDef NVIC_InitStructure;DMA_DeInit(DMA1_Channel2);
DMA_DeInit(DMA1_Channel3);DMA_StructInit(&DMA_InitStructure);
// Enable DMA1 Peripheral Clock (SPI_DECAWAVE and SPI_BUS)
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);// Configure SPI_BUS RX Channel
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; // From SPI to memory DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&SPI1->DR; DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)RxBuffer; DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; DMA_InitStructure.DMA_BufferSize = sizeof(RxBuffer); DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; DMA_InitStructure.DMA_Priority = DMA_Priority_High; DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; DMA_Init(DMA1_Channel2, &DMA_InitStructure);// Configure SPI_BUS TX Channel
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST; // From memory to SPI DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&SPI1->DR; DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)TxBuffer; DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; DMA_InitStructure.DMA_BufferSize = sizeof(TxBuffer);; DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; DMA_InitStructure.DMA_Priority = DMA_Priority_High; DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; DMA_Init(DMA1_Channel3, &DMA_InitStructure);DMA_ITConfig(DMA1_Channel2, DMA_IT_TC, ENABLE);
NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel2_3_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure);}//ReadAddrBuffer = AccelerationRequest with the Register values + DummyByte, Size = 12
void SPI_ReadRegisters(uint8_t* ReadAddrBuffer, uint8_t Size){ for (uint8_t i=0; i < Size; i++) { if (ReadAddrBuffer[i] > 0x00) TxBuffer[i] = ReadAddrBuffer[i] | READ_FLAG; else TxBuffer[i] = 0x00; }DMA_Cmd(DMA1_Channel2, DISABLE);
DMA_Cmd(DMA1_Channel3, DISABLE);DMA_SetCurrDataCounter(DMA1_Channel2, Size);
DMA_SetCurrDataCounter(DMA1_Channel3, Size);SPI_SelectChip();
DMA_Cmd(DMA1_Channel2, ENABLE);
DMA_Cmd(DMA1_Channel3, ENABLE);}void DMA1_Channel2_3_IRQHandler(void){ if (DMA_GetITStatus(DMA1_IT_TC2) != RESET) { SPI_DeselectChip();int16_t x = (int16_t)((RxBuffer[1] << 8) | RxBuffer[0]); // / 16384.0f;
int16_t y = (int16_t)((RxBuffer[3] << 8) | RxBuffer[2]); // / 16384.0f; int16_t z = (int16_t)((RxBuffer[5] << 8) | RxBuffer[4]); // / 16384.0f;DMA_ClearFlag(DMA1_FLAG_TC2);
}}#stm32 #accelerometer #dma #spi2017-07-17 08:02 AM
RxFIFO artefact, together with RXNE not being clear at the moment ?
Try tp test for RXNE and read DR accordingly, before enabling SPI/DMA; and perhaps change RxFIFO level to single byte. The data packing feature might get into way too.
The behaviour of 'advanced' SPI is not very clearly described in the RMs and might require some experimentation.
JW
2017-07-17 11:49 AM
Hello!
what type is RxBuffer ? Is it an array?
in case RxBuffer is a pointer, sizeof(RxBuffer) gives result 4.(32bit). (You have 4 bytes transaction)
2017-07-18 02:11 AM
uint8_t RxBuffer[12];
So the value of DMA_BufferSize should be 1, cause it must be equal with the MemoryDataSize and PeripheralDataSize.
2017-07-18 03:21 AM
No. It's the number of transactions, it is stored into DMA's NDTR register.
uint32_t DMA_BufferSize; /*!< Specifies the buffer size, in data unit, of the specified Stream.
The data unit is equal to the configuration set in DMA_PeripheralDataSize or DMA_MemoryDataSize members depending in the transfer direction. */Once again, read the SPI section thoroughly, focus on FIFO and data packing.
In program, check if RXNE is set before enabling SPI/DMA and read out any outstanding data.
JW
2017-07-18 09:45 AM
Thx for your help. Problem solved
2017-07-18 10:09 AM
How?
2017-07-18 10:46 AM
Before I enable SPI DMA and try to read data I'm doing this:
if (SPI_I2S_GetFlagStatus(SPIx, SPI_I2S_FLAG_RXNE) == SET)
{ uint8_t dummy = SPI1->DR; }I dont enter this functions every time but sometimes - it obv helps - I have more trouble without it.
I had also another problem with my write only function to configure the accelerometer. The µC set the ChipSelect to High while the data transfer was still in progress. But I fixed this issue with checking the SPI Flags SPI_I2S_FLAG_BSY and SPI_I2S_FLAG_TXE.
And ofc changed the DMA_BufferSize and not using sizeof(RxBuffer).