Я работал над контроллером освещения, но мне не повезло в передаче данных через GPIO.Я использую библиотеку STM32F303VCT6 и HAL.В качестве эталона я использовал библиотеку WS2812B для STM32F3 от Hubmartin, модифицировав ее для обработки передачи данных синхронизации светодиодов в одной передаче DMA, в отличие от данных синхронизации битовой полосы в буфер длины двух светодиодов через круговой DMA.
Мой план состоял в том, чтобы использовать DMA для запуска каждого GPIO, для которого установлен светодиодный выход, для вывода «high» в случае обновления таймера.Затем по событию CC1 записать данные выводы в «низкий» через данные буфера.И затем на событии CC2 установить все контакты «низко».Это должно позволить мне обрабатывать данные синхронизации для нескольких полос параллельно.Вот моя реализация:
Чтобы инициализировать таймер:
static void TIM2_init(void){
__HAL_RCC_TIM2_CLK_ENABLE();
tim_period = SystemCoreClock / 800000;
uint32_t cc1 = (10 * tim_period) / 36;
uint32_t cc2 = (10 * tim_period) / 15;
Tim2Handle.Instance = TIM2;
Tim2Handle.Init.Period = tim_period;
Tim2Handle.Init.RepetitionCounter = 0;
Tim2Handle.Init.Prescaler = 0;
Tim2Handle.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
Tim2Handle.Init.CounterMode = TIM_COUNTERMODE_UP;
HAL_TIM_PWM_Init(&Tim2Handle);
tim2OC1.OCMode = TIM_OCMODE_PWM1;
tim2OC1.OCPolarity = TIM_OCPOLARITY_HIGH;
tim2OC1.Pulse = cc1;
tim2OC1.OCFastMode = TIM_OCFAST_DISABLE;
HAL_TIM_PWM_ConfigChannel(&Tim2Handle, &tim2OC1, TIM_CHANNEL_1);
tim2OC2.Pulse = cc2;
HAL_TIM_PWM_ConfigChannel(&Tim2Handle, &tim2OC2, TIM_CHANNEL_2);
}
Чтобы инициализировать DMA:
static void DMA_init(void){
__HAL_RCC_DMA1_CLK_ENABLE();
dmaUpdate.Init.Direction = DMA_MEMORY_TO_PERIPH;
dmaUpdate.Init.PeriphInc = DMA_PINC_DISABLE;
dmaUpdate.Init.MemInc = DMA_MINC_DISABLE;
dmaUpdate.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
dmaUpdate.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
dmaUpdate.Init.Mode = DMA_NORMAL;
dmaUpdate.Init.Priority = DMA_PRIORITY_VERY_HIGH;
dmaUpdate.Instance = DMA1_Channel2;
HAL_DMA_Init(&dmaUpdate);
__HAL_LINKDMA(&Tim2Handle, hdma[TIM_DMA_ID_UPDATE], dmaUpdate);
dmaCC1.Init.Direction = DMA_MEMORY_TO_PERIPH;
dmaCC1.Init.PeriphInc = DMA_PINC_DISABLE;
dmaCC1.Init.MemInc = DMA_MINC_ENABLE;
dmaCC1.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
dmaCC1.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
dmaCC1.Init.Mode = DMA_NORMAL;
dmaCC1.Init.Priority = DMA_PRIORITY_VERY_HIGH;
dmaCC1.Instance = DMA1_Channel5;
HAL_DMA_Init(&dmaCC1);
__HAL_LINKDMA(&Tim2Handle, hdma[TIM_DMA_ID_CC1], dmaCC1);
dmaCC2.Init.Direction = DMA_MEMORY_TO_PERIPH;
dmaCC2.Init.PeriphInc = DMA_PINC_DISABLE;
dmaCC2.Init.MemInc = DMA_MINC_DISABLE;
dmaCC2.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
dmaCC2.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
dmaCC2.Init.Mode = DMA_NORMAL;
dmaCC2.Init.Priority = DMA_PRIORITY_VERY_HIGH;
dmaCC2.Instance = DMA1_Channel7;
HAL_DMA_Init(&dmaCC2);
__HAL_LINKDMA(&Tim2Handle, hdma[TIM_DMA_ID_CC2], dmaCC2);
dmaCC2.XferCpltCallback = DMA_TransferCompleteHandler;
HAL_NVIC_SetPriority(DMA1_Channel7_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(DMA1_Channel7_IRQn);
}
Чтобы начать передачу:
static void WS2812_sendbuf(){
ws2812b.transferComplete = 0;
HAL_DMA_Start(&dmaUpdate,(uint32_t)WS2812_IO_High, (uint32_t)&WS2812B_PORT->BSRR, BUFFER_SIZE);
HAL_DMA_Start(&dmaCC1,(uint32_t)ws2812bDmaBitBuffer, (uint32_t)&WS2812B_PORT->BRR, BUFFER_SIZE);
HAL_DMA_Start_IT(&dmaCC2,(uint32_t)WS2812_IO_Low, (uint32_t)&WS2812B_PORT->BSRR, BUFFER_SIZE);
__HAL_TIM_ENABLE_DMA(&Tim2Handle, TIM_DMA_UPDATE);
__HAL_TIM_ENABLE_DMA(&Tim2Handle, TIM_DMA_CC1);
__HAL_TIM_ENABLE_DMA(&Tim2Handle, TIM_DMA_CC2);
__HAL_TIM_ENABLE(&Tim2Handle);
}
Для обратного вызова при завершении вывода DMA:
void DMA1_Channel7_IRQHandler(void){
HAL_DMA_IRQHandler(&dmaCC2);
}
void DMA_TransferCompleteHandler(DMA_HandleTypeDef *DmaHandle){
WS2812B_PORT->BSRR = WS2812_IO_Low[0];
__HAL_TIM_DISABLE_DMA(&Tim2Handle, TIM_DMA_UPDATE);
__HAL_TIM_DISABLE_DMA(&Tim2Handle, TIM_DMA_CC1);
__HAL_TIM_DISABLE_DMA(&Tim2Handle, TIM_DMA_CC2);
__HAL_TIM_DISABLE(&Tim2Handle);
ws2812b.transferComplete = 1;
}
Хотя я могу убедиться, что начальная реализация работает, как и было задумано, в текущем драйвере HAL есть некоторое странное поведение, которое я пытаюсь преодолеть, имея все своиданные доступны до начала передачи данных о времени.
В моей текущей реализации я отправляю один буфер данных и начинаю передачу данных синхронизации, а затем задерживаю 100 миллисекунд, прежде чем снова начать процесс.Я смущен, обнаружив, что моя реализация вообще не отправляет какие-либо данные через GPIO, и я предполагаю, что допустил ошибки при запуске логики состояния / таймера.Кто-нибудь видит ошибку, которую я сделал, чтобы не выводить?