High frequency streaming
Re: High frequency streaming
Hi,
Thanks for your input.
I have managed to put the sampling working with a TIMx timer, specifically TIM6 by adapting the example I mentioned and everything is more or less working. I'll now add DMA to make it run smoothly in case of higher sampling frequencies.
Thanks for your input.
I have managed to put the sampling working with a TIMx timer, specifically TIM6 by adapting the example I mentioned and everything is more or less working. I'll now add DMA to make it run smoothly in case of higher sampling frequencies.
Re: High frequency streaming
Hi everyone,
In the past week I have been working on DMA and it's not going that well... Is there anyone here that knows how to do it properly? I'll explain my problem...
I want to read an analog value and that is working, I don't think that it is implemented the most efficient way, but it works for now. After this I want to use DMA to read 19 values, one at the time, from the ADC1 and then send an IRQ to handle the data.
This is the code for setting up the DMA:
This is the code related to ADC1 and DMA:
And to handle the data:
When I flash this into the Crazyflie it crashes (the 2 lights stay blue and doesn't do the normal boot led sequence). I have been looking around and when I change the DMA_Channel to DMA_Channel1 for example it doesn't crash, but I have to use that because of the mapping.
Thanks in advance.
In the past week I have been working on DMA and it's not going that well... Is there anyone here that knows how to do it properly? I'll explain my problem...
I want to read an analog value and that is working, I don't think that it is implemented the most efficient way, but it works for now. After this I want to use DMA to read 19 values, one at the time, from the ADC1 and then send an IRQ to handle the data.
This is the code for setting up the DMA:
Code: Select all
#define DMA_Str DMA2_Stream4
#define DMA_IRQ DMA2_Stream4_IRQn
void DMA_init(volatile uint16_t *ADCConvertedValue)
{
DMA_InitTypeDef DMA_InitStructure;
DMA_StructInit(&DMA_InitStructure);
//==Configure DMA2 - Stream 4
DMA_DeInit(DMA_Str); //Set DMA registers to default values
DMA_InitStructure.DMA_Channel = DMA_Channel_0;
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR; //Source address
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t) ADCConvertedValue; //Destination address
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
DMA_InitStructure.DMA_BufferSize = 19; //Buffer size
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; //source size - 16bit
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; // destination size = 16b
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
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_Init(DMA_Str, &DMA_InitStructure); //Initialize the DMA
DMA_Cmd(DMA_Str, ENABLE); //Enable the DMA2 - Stream 4
DMA_ITConfig(DMA_Str, DMA_IT_TC, ENABLE);
//Enable DMA1 channel IRQ Channel
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = DMA_IRQ;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
Code: Select all
ADC_RegularChannelConfig(ADC_NUM, ADC_CHANNEL, 1, ADC_SampleTime_144Cycles);
ADC_DMACmd(ADC_NUM, ENABLE); //Enable ADC1 DMA
ADC_DMARequestAfterLastTransferCmd(ADC_NUM, ENABLE);
ADC_Cmd(ADC_NUM, ENABLE);
ADC_start();
Code: Select all
void DMA2_Stream4_IRQHandler(void)
{
if (DMA_GetITStatus(DMA2_Stream4, DMA_IT_TC)) {
// My code
DMA_ClearITPendingBit(DMA2_Stream4, DMA_IT_TC);
}
}
Thanks in advance.
Re: High frequency streaming
Hi,
Without doing any detailed analysis it looks OK to me and the resources does not seem occupied by something else. Could it be that the code ends up in an endless looping interrupt? If you have the code at github I can do a quick SWD debug of it.
Without doing any detailed analysis it looks OK to me and the resources does not seem occupied by something else. Could it be that the code ends up in an endless looping interrupt? If you have the code at github I can do a quick SWD debug of it.
Re: High frequency streaming
Hi,
Sorry it took me so long. I wasn't working on github but I am now. If you have the time please take a look at the micdeck files here. I think the timer and the ADC can be connected some other way, I still haven't figured it out, but that part I think is working only when I turn on DMA the Crazyflie crashes.
Thank you
Edit: I added the python script I'm using to unpack and display the data to a new repository
Edit2: I just realized that I spent a bunch of time on the internet looking how to work with timers and DMA when I could just have looked into ledring12 files... And I realized that I'm not setting the .usedGpio and .usedPeriph well.
Sorry it took me so long. I wasn't working on github but I am now. If you have the time please take a look at the micdeck files here. I think the timer and the ADC can be connected some other way, I still haven't figured it out, but that part I think is working only when I turn on DMA the Crazyflie crashes.
Thank you
Edit: I added the python script I'm using to unpack and display the data to a new repository
Edit2: I just realized that I spent a bunch of time on the internet looking how to work with timers and DMA when I could just have looked into ledring12 files... And I realized that I'm not setting the .usedGpio and .usedPeriph well.
Re: High frequency streaming
I quickly tested you code and as I suspected it gets stuck in an endless interrupt, namely the DMA2 interrupt. Something more (flag) needs to be cleared or interrupt inactivated. The half transfer flag was set I could see.
I see that you use the timer interrupt to trigger the DMA. You can set this up directly so the timer will trigger the ADC and the ADC will trigger the DMA. You can then use the half transfer and transfer complete interrupt with a circular buffer to constantly get ADC values and minimize CPU load.
Hope the above helps!
I see that you use the timer interrupt to trigger the DMA. You can set this up directly so the timer will trigger the ADC and the ADC will trigger the DMA. You can then use the half transfer and transfer complete interrupt with a circular buffer to constantly get ADC values and minimize CPU load.
Hope the above helps!
Re: High frequency streaming
Hi,
Thank you for the tips. I had some stuff wrong.
Firstly I forgot to change the RCC_AHB1Periph_DMA2 to enable, but worst than that was an error in clearing the interruption bit. I had DMA_ClearITPendingBit(DMA2_Stream4, DMA_IT_TC); instead of DMA_ClearITPendingBit(DMA2_Stream4, DMA_IT_TCIF4); and since those are unsigned ints the compiler didn't complained.
Regarding the ADC and the timer, I finally took the time to see how to do it properly and it wasn't that difficult. I'm now using the TIM3 since I couldn't use TIM6. After this the Crazyflie started crashing randomly (2 red leds on). I thought it was because I wasn't implementing the last step (using the half transfer) but after implementing that the crashes continue, some times it takes 1 sec sometimes 10 sec.
I'll continue to push on this and I'll let you know how it turned out. I guess STM32F4 has a thing called double buffering which is similar to use HT and TC, if I can't find the source of the crashes I'll give this a try.
Thanks again!
Thank you for the tips. I had some stuff wrong.
Firstly I forgot to change the RCC_AHB1Periph_DMA2 to enable, but worst than that was an error in clearing the interruption bit. I had DMA_ClearITPendingBit(DMA2_Stream4, DMA_IT_TC); instead of DMA_ClearITPendingBit(DMA2_Stream4, DMA_IT_TCIF4); and since those are unsigned ints the compiler didn't complained.
Regarding the ADC and the timer, I finally took the time to see how to do it properly and it wasn't that difficult. I'm now using the TIM3 since I couldn't use TIM6. After this the Crazyflie started crashing randomly (2 red leds on). I thought it was because I wasn't implementing the last step (using the half transfer) but after implementing that the crashes continue, some times it takes 1 sec sometimes 10 sec.
I'll continue to push on this and I'll let you know how it turned out. I guess STM32F4 has a thing called double buffering which is similar to use HT and TC, if I can't find the source of the crashes I'll give this a try.
Thanks again!
Re: High frequency streaming
Hi again,
I found out why the Crazyflie was crashing, the priority for the DMA NVIC IRQ was too high. I guess there was some functionality of the FreeRTOS that didn't had the time to run.
So I have been looking into optimization since I'm already having problems with what I think is CPU load and I found out that the function I have been using to send packets (crtpSendPacket) uses a function (xQueueSend) which "...must not be called from an interrupt service routine." and queues the packets by copy and not by reference. Due to this I created a new crtpSendPacketISR function which uses xQueueSendFromISR instead, even if this funtion queues packets by copy too.
It works, but does this sounds ok to you? Do you have any other suggestion on how to make the sending of packets more efficient, maybe creating a function which queues the packets by reference?
Thank you
Edit:
This is my DMA IRQ.
I found out why the Crazyflie was crashing, the priority for the DMA NVIC IRQ was too high. I guess there was some functionality of the FreeRTOS that didn't had the time to run.
So I have been looking into optimization since I'm already having problems with what I think is CPU load and I found out that the function I have been using to send packets (crtpSendPacket) uses a function (xQueueSend) which "...must not be called from an interrupt service routine." and queues the packets by copy and not by reference. Due to this I created a new crtpSendPacketISR function which uses xQueueSendFromISR instead, even if this funtion queues packets by copy too.
Code: Select all
int crtpSendPacketISR(CRTPPacket *p)
{
ASSERT(p);
ASSERT(p->size <= CRTP_MAX_DATA_SIZE);
return xQueueSendFromISR(txQueue, p, 0);
}
Thank you
Edit:
This is my DMA IRQ.
Code: Select all
void packsData(uint8_t section) {
p.data[0] = packetCount;
packetCount++;
ptr = 1;
byteHalf = 0;
i = SAMPLES_PER_PACKET * section;
end = SAMPLES_PER_PACKET * (section + 1);
do{
sample = ADCConvertedValue[i];
if(byteHalf){
p.data[ptr] |= (uint8_t)(sample >> 8);
ptr++;
p.data[ptr] = (uint8_t)(sample);
ptr++;
byteHalf = 0;
}else{
p.data[ptr] = (uint8_t)(sample >> 4);
ptr++;
p.data[ptr] = (uint8_t)(sample << 4);
byteHalf = 1;
}
i++;
}while(i != end);
crtpSendPacketISR(&p);
memset(&(p.data[1]), 0, DATA_BYTES);
}
Re: High frequency streaming
Good findings!
It might be efficient enough now but I think you can make it much more efficient by letting the ADC and DMA do all the work. You could setup a 60 byte buffer and have the DMA work in circular mode and use HT and TC interrupts to just send the buffer that is not in use for the moment. The DMA and ADC can be setup to handle the 12bit and put it in words so you don't have to do that either.
It might be efficient enough now but I think you can make it much more efficient by letting the ADC and DMA do all the work. You could setup a 60 byte buffer and have the DMA work in circular mode and use HT and TC interrupts to just send the buffer that is not in use for the moment. The DMA and ADC can be setup to handle the 12bit and put it in words so you don't have to do that either.
Re: High frequency streaming
I'm already doing that. That function is called in the DMA interrupt:
Sorry I forgot to mention.
Code: Select all
void DMA2_Stream4_IRQHandler(void)
{
if (DMA_GetITStatus(DMA2_Stream4, DMA_IT_HTIF4)) {
packsData(0);
DMA_ClearITPendingBit(DMA2_Stream4, DMA_IT_HTIF4);
}
if (DMA_GetITStatus(DMA2_Stream4, DMA_IT_TCIF4)) {
packsData(1);
DMA_ClearITPendingBit(DMA2_Stream4, DMA_IT_TCIF4);
}
}
Re: High frequency streaming
Btw I'm experiencing something I believe is some kind of interference from the packet sending. Did you ever seen something like this on readings from the adc? For some reason this noise almost disappears when the ground of the Crazyflie is connected to my oscilloscope...