A new question occurred while using this to continue writing code.
We are experimenting with replacing the existing pb5 port with pb8.
Tim3 and Tim4 have not been further modified for the period because they have confirmed that they have the same performance on the datasheet.
And I changed the existing dma stream 5 to stream 7 and changed the time3_ch2 to tim4_ch3.
But the result was different from what I thought.
Is there anything else I need to know to succeed in this?
By default, timer channel, dma stream, dma channel, and dma interrupt number have been replaced only within the current code.
Q : What part of my code should I modify?
Code: Select all
#include <string.h>
// ST lib includes
#include "stm32fxxx.h"
#include "nvicconf.h"
#include "FreeRTOS.h"
#include "semphr.h"
//#define TIM1_CCR1_Address 0x40012C34 // physical memory address of Timer 3 CCR1 register
static TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
static TIM_OCInitTypeDef TIM_OCInitStructure;
static GPIO_InitTypeDef GPIO_InitStructure;
static DMA_InitTypeDef DMA_InitStructure;
static NVIC_InitTypeDef NVIC_InitStructure;
static xSemaphoreHandle allLedDone = NULL;
// The minimum is to have 2 leds (1 per half buffer) in the buffer, this
// consume 42Bytes and will trigger the DMA interrupt at ~2KHz.
// Putting 2 there will divide by 2 the interrupt frequency but will also
// double the memory consumption (no free lunch ;-)
#define LED_PER_HALF 1
#define TIMING_ONE 75
#define TIMING_ZERO 29
static union {
uint16_t buffer[2*LED_PER_HALF*24];
struct {
uint16_t begin[LED_PER_HALF*24];
uint16_t end[LED_PER_HALF*24];
} __attribute__((packed));
} led_dma;
void ws2812Init(void)
{
uint16_t PrescalerValue;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);
/* GPIOB Configuration: TIM4 Channel 1 as alternate function push-pull */
// Configure the GPIO PB4 for the timer output
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_25MHz;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
GPIO_Init(GPIOB, &GPIO_InitStructure);
//Map timer to alternate functions
GPIO_PinAFConfig(GPIOB, GPIO_PinSource8, GPIO_AF_TIM4);
/* Compute the prescaler value */
PrescalerValue = 0;
/* Time base configuration */
TIM_TimeBaseStructure.TIM_Period = (105 - 1); // 800kHz
TIM_TimeBaseStructure.TIM_Prescaler = PrescalerValue;
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure);
/* PWM1 Mode configuration: Channel1 */
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = 0;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OC3Init(TIM4, &TIM_OCInitStructure);
// TIM_Cmd(TIM4, ENABLE); // Go!!!
TIM_OC3PreloadConfig(TIM4, TIM_OCPreload_Enable);
TIM_CtrlPWMOutputs(TIM4, ENABLE); // enable Timer 3
/* configure DMA */
/* DMA clock enable */
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE);
/* DMA1 Channel5 Config TM */
DMA_DeInit(DMA1_Stream7);
ASSERT_DMA_SAFE(led_dma.buffer);
// USART TX DMA Channel Config
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&TIM4->CCR3;
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)led_dma.buffer; // this is the buffer memory
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
DMA_InitStructure.DMA_BufferSize = 0;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_1QuarterFull ;
DMA_InitStructure.DMA_Channel = DMA_Channel_2;
DMA_Init(DMA1_Stream7, &DMA_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = DMA1_Stream7_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = NVIC_LOW_PRI;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
vSemaphoreCreateBinary(allLedDone);
DMA_ITConfig(DMA1_Stream7, DMA_IT_TC, ENABLE);
DMA_ITConfig(DMA1_Stream7, DMA_IT_HT, ENABLE);
/* TIM4 CC2 DMA Request enable */
TIM_DMACmd(TIM4, TIM_DMA_CC3, ENABLE);
}
static void fillLed(uint16_t *buffer, uint8_t *color)
{
int i;
for(i=0; i<8; i++) // GREEN data
{
buffer[i] = ((color[1]<<i) & 0x0080) ? TIMING_ONE:TIMING_ZERO;
}
for(i=0; i<8; i++) // RED
{
buffer[8+i] = ((color[0]<<i) & 0x0080) ? TIMING_ONE:TIMING_ZERO;
}
for(i=0; i<8; i++) // BLUE
{
buffer[16+i] = ((color[2]<<i) & 0x0080) ? TIMING_ONE:TIMING_ZERO;
}
}
static int current_led = 0;
static int total_led = 0;
static uint8_t (*color_led)[3] = NULL;
void ws2812Send(uint8_t (*color)[3], uint16_t len)
{
int i;
if(len<1) return;
//Wait for previous transfer to be finished
xSemaphoreTake(allLedDone, portMAX_DELAY);
// Set interrupt context ...
current_led = 0;
total_led = len;
color_led = color;
for(i=0; (i<LED_PER_HALF) && (current_led<total_led+2); i++, current_led++) {
if (current_led<total_led)
fillLed(led_dma.begin+(24*i), color_led[current_led]);
else
bzero(led_dma.begin+(24*i), sizeof(led_dma.begin));
}
for(i=0; (i<LED_PER_HALF) && (current_led<total_led+2); i++, current_led++) {
if (current_led<total_led)
fillLed(led_dma.end+(24*i), color_led[current_led]);
else
bzero(led_dma.end+(24*i), sizeof(led_dma.end));
}
DMA1_Stream7->NDTR = sizeof(led_dma.buffer) / sizeof(led_dma.buffer[0]); // load number of bytes to be transferred
DMA_Cmd(DMA1_Stream7, ENABLE); // enable DMA channel 2
TIM_Cmd(TIM4, ENABLE); // Go!!!
}
void ws2812DmaIsr(void)
{
portBASE_TYPE xHigherPriorityTaskWoken;
uint16_t * buffer;
int i;
if (total_led == 0)
{
TIM_Cmd(TIM4, DISABLE);
DMA_Cmd(DMA1_Stream7, DISABLE);
}
if (DMA_GetITStatus(DMA1_Stream7, DMA_IT_HTIF7))
{
DMA_ClearITPendingBit(DMA1_Stream7, DMA_IT_HTIF7);
buffer = led_dma.begin;
}
if (DMA_GetITStatus(DMA1_Stream7, DMA_IT_TCIF7))
{
DMA_ClearITPendingBit(DMA1_Stream7, DMA_IT_TCIF7);
buffer = led_dma.end;
}
for(i=0; (i<LED_PER_HALF) && (current_led<total_led+2); i++, current_led++) {
if (current_led<total_led)
fillLed(buffer+(24*i), color_led[current_led]);
else
bzero(buffer+(24*i), sizeof(led_dma.end));
}
if (current_led >= total_led+2) {
xSemaphoreGiveFromISR(allLedDone, &xHigherPriorityTaskWoken);
TIM_Cmd(TIM4, DISABLE); // disable Timer 3
DMA_Cmd(DMA1_Stream7, DISABLE); // disable DMA Stream7
total_led = 0;
}
}
#ifndef USDDECK_USE_ALT_PINS_AND_SPI
void __attribute__((used)) DMA1_Stream7_IRQHandler(void)
{
ws2812DmaIsr();
}
#endif
One suspicious part is 'DMA1_Stream7_IRQn'.
I didn't know exactly what function this was set.
---------------------------------------------------------------------------------------------------------------------------------------------------------------------
I conducted an additional experiment over the weekend.
Immediately after starting the cracyfly, we determined that the waveform and subsequent waveforms were different.
Before "Ready to fly" was output from the console of the client, the waveform was output normally and then the output changed.
1. before print "Ready to fly", same as normal code
- 1.GIF (20.59 KiB) Viewed 1757 times
2. after print "Ready to fly"
- 2.GIF (21.06 KiB) Viewed 1757 times
Regardless of the existing code, the same waveform is output, but the changed code has identified the different house.
Therefore, I don't think it's a problem with rtos, and I doubt the possibility of changing the timer or dma setting in the middle.
In other words, I think this situation can occur by setting different settings for the timer or dma_stream that I want to write to in the middle of a different file.
1. I wrote the wrong code.
2. The code has no problem, but changes the setting for the corresponding timer (TIM4_CH3) or DAM_STREAM7 in another function or task.
Do you have any other ideas related to this?