Форум РадиоКот • Просмотр темы - CH32V и лента WS2812
Сообщения без ответов | Активные темы
Страница 1 из 1
[ Сообщений: 11 ]
Автор
Сообщение
dmitrij999
Заголовок сообщения: CH32V и лента WS2812
Добавлено: Вт май 16, 2023 11:05:43
Зарегистрирован: Ср дек 25, 2019 23:41:33Сообщений: 43
Рейтинг сообщения: 0
Всем привет!
Пытаюсь реализовать управление WS2812 с RISC-V контроллера CH32V307 (потом перенесу код на CH32V003) по образу и подобию с руководства по STM32:
здесь. Тактирование 96 МГц, выдать пачку импульсов не удается, прерывания по DMA не выдаются. По логическому анализатору импульс выдается на сбросе.
Подскажите, что не так
Код под спойлером
Спойлер main.cКод:
/********************************** (C) COPYRIGHT ******************************* * File Name : main.c * Author : WCH * Version : V1.0.0 * Date : 2021/06/06 * Description : Main program body. ********************************************************************************* * Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd. * Attention: This software (modified or not) and binary are used for * microcontroller manufactured by Nanjing Qinheng Microelectronics. *******************************************************************************/ /* *@Note USART Print debugging routine: USART1_Tx(PA9). This example demonstrates using USART1(PA9) as a print debug port output. */ #include "debug.h" #include "ws2812.h" /* Global typedef */ /* Global define */ /* Global Variable */ //TIM_TypeDef timer_handle; TIM_TimeBaseInitTypeDef time_base_init = {0}; TIM_OCInitTypeDef timer_output_cfg = {0}; DMA_InitTypeDef dma_leds = {0}; void Timer_PWM_Init(); void DMA_LEDs_Init(); /********************************************************************* * @fn main * * @brief Main program. * * @return none */ int main(void) { NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); SystemCoreClockUpdate(); Delay_Init(); USART_Printf_Init(115200); printf("SystemClk:%d\r\n",SystemCoreClock); printf( "ChipID:%08x\r\n", DBGMCU_GetCHIPID() ); printf("This is printf example\r\n"); Timer_PWM_Init(); DMA_LEDs_Init(); // while(DMA_GetFlagStatus(DMA1_FLAG_TC1) == RESET); ws2812_init(TIM1); ws2812_set_pixel(0, 0, 0, 0); ws2812_show(); int i = 0; while(1) { printf("OK\r\n"); Delay_Ms(1000); ws2812_set_pixel(0, i++, 0, 0); ws2812_show(); } } // Init Timer for PWM (PA8) void Timer_PWM_Init() { GPIO_InitTypeDef GPIO_PWMInitStructure={0}; RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA | RCC_APB2Periph_TIM1, ENABLE ); GPIO_PWMInitStructure.GPIO_Pin = GPIO_Pin_8; GPIO_PWMInitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_PWMInitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init( GPIOA, &GPIO_PWMInitStructure ); // GPIO_PinRemapConfig(AFIO_PCFR1_PD01_REMAP, DISABLE); time_base_init.TIM_ClockDivision = TIM_CKD_DIV1; time_base_init.TIM_Period = 126; time_base_init.TIM_CounterMode = TIM_CounterMode_Up; time_base_init.TIM_Prescaler = 0; time_base_init.TIM_RepetitionCounter = 0; TIM_TimeBaseInit(TIM1, &time_base_init); timer_output_cfg.TIM_OCMode = TIM_OCMode_PWM1; timer_output_cfg.TIM_OutputState = TIM_OutputState_Enable; timer_output_cfg.TIM_OCPolarity = TIM_OCPolarity_High; // timer_output_cfg.TIM_OCIdleState = 0; // timer_output_cfg.TIM_OCNIdleState = 0; timer_output_cfg.TIM_Pulse = 0; // TIM_DMAConfig(TIM1, TIM_DMABase, TIM_DMABurstLength) TIM_OC1Init(TIM1, &timer_output_cfg); TIM_CtrlPWMOutputs(TIM1, ENABLE ); TIM_OC1PreloadConfig( TIM1, TIM_OCPreload_Disable ); TIM_ARRPreloadConfig( TIM1, ENABLE ); TIM_Cmd( TIM1, ENABLE ); } void DMA_LEDs_Init() { RCC_AHBPeriphClockCmd( RCC_AHBPeriph_DMA1, ENABLE ); NVIC_SetPriority(DMA1_Channel1_IRQn,0xE0); NVIC_EnableIRQ(DMA1_Channel1_IRQn); dma_leds.DMA_PeripheralBaseAddr = (u32)TIM1->DMAADR; dma_leds.DMA_MemoryBaseAddr = (u32)get_ws2812b_array_ptr(); dma_leds.DMA_DIR = DMA_DIR_PeripheralDST; dma_leds.DMA_BufferSize = LED_ARRAY_LEN*2; dma_leds.DMA_PeripheralInc = DMA_PeripheralInc_Disable; dma_leds.DMA_MemoryInc = DMA_MemoryInc_Enable; dma_leds.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; dma_leds.DMA_MemoryDataSize = DMA_PeripheralDataSize_HalfWord; dma_leds.DMA_Mode = DMA_Mode_Normal; dma_leds.DMA_Priority = DMA_Priority_High; dma_leds.DMA_M2M = DMA_M2M_Disable; DMA_Init(DMA1_Channel1, &dma_leds); DMA_ITConfig(DMA1_Channel1,DMA_IT_TC,ENABLE); DMA_ClearFlag(DMA1_FLAG_TC1); DMA_Cmd(DMA1_Channel1, ENABLE); } /********************************************************************* * @fn DMA1_Channel1_IRQHandler * * @brief This function DMA1 Channel1 exception. * * @return none */ void DMA1_Channel1_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast"))); void DMA1_Channel1_IRQHandler(void) { if(DMA_GetITStatus(DMA1_IT_TC1)) { // TIM_Cmd(TIM1, DISABLE); // TIM_DMACmd(TIM1, DMA1_Channel1, NewState) DMA_ClearITPendingBit(DMA1_IT_TC1|DMA1_IT_GL1|DMA1_IT_HT1); } }
ws2812.cКод:
/* * ws2812.c * * Created on: May 4, 2023 * Author: dmitr */ #include "ws2812.h" uint16_t BUF_DMA[LED_ARRAY_LEN] = {0}; TIM_TypeDef * timer_handle = NULL; int ws2812_init(TIM_TypeDef * th) { if (!th) return -1; else timer_handle = th; ws2812_clear_buffer(); return 0; } void ws2812_clear_buffer() { for(int i=0;i<(LED_ARRAY_LEN-DELAY_LEN);i++) BUF_DMA[i] = LOW; } uint32_t * get_ws2812b_array_ptr() { return &BUF_DMA; } void byte_to_sequence(uint8_t byte_to_convert, uint16_t * seq) { for (int i = 7; i <= 0; i--) { if (((byte_to_convert>>i) & 1) == 0) seq[i] = LOW; else seq[i] = HIGH; } } void copy_sequence_to_position(uint32_t position, int sp_offset, uint16_t * seq, uint16_t * led_array) { if (position > LED_COUNT) position = LED_COUNT; if (sp_offset > 2) sp_offset = 2; if (sp_offset < 0) sp_offset = 0; for (int i = 0; i < 8; i++) led_array[position+8*sp_offset+i] = seq[i]; } void ws2812_set_pixel(uint32_t pixel_num, uint8_t r, uint8_t g, uint8_t b) { if (pixel_num > LED_COUNT) pixel_num = LED_COUNT; uint16_t tmp[8]; byte_to_sequence(r, &tmp); copy_sequence_to_position(pixel_num, 0, &tmp, &BUF_DMA); byte_to_sequence(g, &tmp); copy_sequence_to_position(pixel_num, 1, &tmp, &BUF_DMA); byte_to_sequence(b, &tmp); copy_sequence_to_position(pixel_num, 2, &tmp, &BUF_DMA); } void ws2812_show() { DMA_Cmd(DMA1_Channel1, ENABLE); }
ws2812.hКод:
/* * ws2812.h * * Created on: May 4, 2023 * Author: dmitr */ #ifndef USER_WS2812_H_ #define USER_WS2812_H_ #include "stdio.h" #include "stdint.h" #include "ch32v30x.h" #include "ch32v30x_tim.h" #include "ch32v30x_dma.h" //---------- #define DELAY_LEN 48 #define LED_COUNT 8 #define LED_ARRAY_LEN DELAY_LEN + LED_COUNT*24 #define HIGH 0x8A3D // 54% #define LOW 0x3AE1 // 23% int ws2812_init(TIM_TypeDef * th); uint32_t * get_ws2812b_array_ptr(); void ws2812_set_pixel(uint32_t pixel_num, uint8_t r, uint8_t g, uint8_t b); void ws2812_clear_buffer(); void ws2812_show(); #endif /* USER_WS2812_H_ */
Добавлено after 42 minutes 54 seconds: Настроил логический анализатор на большую частоту выборок. При настройке Pulse выдается ШИМ, норм
Но DMA не работает
Вернуться наверх
Реклама
VladislavS
Заголовок сообщения: Re: CH32V и лента WS2812
Добавлено: Ср май 17, 2023 08:51:29
Собутыльник Кота
Карма: 18
Рейтинг сообщений: 433
Зарегистрирован: Вт май 01, 2018 19:44:47Сообщений: 2557
Рейтинг сообщения: 0
TIM1 точно на DMA1 Chanel11 заведён?
Спойлер Вложение:
Вернуться наверх
Реклама
>TEHb<
Заголовок сообщения: Re: CH32V и лента WS2812
Добавлено: Ср май 17, 2023 13:05:45
Друг Кота
Карма: 17
Рейтинг сообщений: 467
Зарегистрирован: Ср ноя 11, 2009 17:19:30Сообщений: 5594Откуда: Воронеж
Рейтинг сообщения: 0
Может у них тоже чертовщина всякая с запросами ПДП настраивается в SYSCFG? Ну или что у них там в качестве аналога.
_________________ "Привет!" - соврал он.
Вернуться наверх
dmitrij999
Заголовок сообщения: Re: CH32V и лента WS2812
Добавлено: Ср май 17, 2023 13:07:02
Зарегистрирован: Ср дек 25, 2019 23:41:33Сообщений: 43
Рейтинг сообщения: 0
Так, теперь прерывание приходит, но один раз
И принцип, я так понимаю, такой: на таймере надо включить выход запроса DMA с определенного канала, с которого выдается ШИМ, активировать сам DMA, написать обработчик, а связь между запросом DMA и каналом таймера задана уже в железе
Код обработчика прерываний DMA
Код:
void DMA1_Channel2_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast"))); void DMA1_Channel2_IRQHandler(void) { if(DMA_GetITStatus(DMA1_IT_TC2) != RESET) { DMA_ClearITPendingBit(DMA1_IT_TC2); } if (TIM_GetITStatus(TIM1, TIM_IT_CC1) != RESET) { TIM_ClearITPendingBit(TIM1, TIM_IT_CC1); } // Вставить настройку таймера для нового запроса // time_base_init.TIM_Period = 126; TIM1->CNT = 0; DMA_Cmd(DMA1_Channel2, DISABLE); TIM_DMACmd(TIM1, TIM_DMA_CC1, DISABLE); TIM_Cmd(TIM1, DISABLE); TIM_ITConfig(TIM1, TIM_IT_CC1, DISABLE); TIM_CCxCmd(TIM1, TIM_Channel_1, TIM_CCx_Disable); x++; }
Запуск вывода
Код:
void ws2812_show() { TIM_DMACmd(TIM1, TIM_DMA_CC1, ENABLE); TIM_CCxCmd(TIM1, TIM_Channel_1, TIM_CCx_Enable); TIM_Cmd(TIM1, ENABLE); NVIC_EnableIRQ(DMA1_Channel2_IRQn); DMA_Cmd(DMA1_Channel2, ENABLE); }
Вернуться наверх
Реклама
VladislavS
Заголовок сообщения: Re: CH32V и лента WS2812
Добавлено: Ср май 17, 2023 17:30:47
Собутыльник Кота
Карма: 18
Рейтинг сообщений: 433
Зарегистрирован: Вт май 01, 2018 19:44:47Сообщений: 2557
Рейтинг сообщения: 0
А где вы его включаете, чтобы оно много раз происходило?
Вернуться наверх
Реклама
dmitrij999
Заголовок сообщения: Re: CH32V и лента WS2812
Добавлено: Ср май 17, 2023 17:42:38
Зарегистрирован: Ср дек 25, 2019 23:41:33Сообщений: 43
Рейтинг сообщения: 0
DMA должно включаться каждый раз, когда вызываю ws2812_show(), вызывается каждые 100 мс
Вернуться наверх
Реклама
dmitrij999
Заголовок сообщения: Re: CH32V и лента WS2812
Добавлено: Чт май 18, 2023 11:57:34
Зарегистрирован: Ср дек 25, 2019 23:41:33Сообщений: 43
Рейтинг сообщения: 0
Помогло от одноразовой отправки вот что: перед отправкой семплов сбрасываю счетчик отправленных данных DMA DMA_SetCurrDataCounter(DMA1_Channel2, LED_ARRAY_LEN);
Вернуться наверх
VladislavS
Заголовок сообщения: Re: CH32V и лента WS2812
Добавлено: Чт май 18, 2023 12:20:56
Собутыльник Кота
Карма: 18
Рейтинг сообщений: 433
Зарегистрирован: Вт май 01, 2018 19:44:47Сообщений: 2557
Рейтинг сообщения: 0
Только не сбрасываете, а задаёте количество передаваемых данных.
Вернуться наверх
dmitrij999
Заголовок сообщения: Re: CH32V и лента WS2812
Добавлено: Сб май 20, 2023 01:10:11
Зарегистрирован: Ср дек 25, 2019 23:41:33Сообщений: 43
Рейтинг сообщения: 0
Теперь другая проблема: посылка не отправляется в нужном формате
Решил проверить работу ШИМ, заодно и подкорректировать значения ШИМ для 0 и 1.
В итоге, засовываю в регистр CH1CVR значение для низкого уровня, получаю такую картину:
https://disk.yandex.ru/i/-wFed6Js7Ke30g Код для инициализации таймера:
Код:
// Init Timer for PWM (PA8) void Timer_PWM_Init() { GPIO_InitTypeDef GPIO_PWMInitStructure={0}; RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA | RCC_APB2Periph_TIM1, ENABLE ); GPIO_PWMInitStructure.GPIO_Pin = GPIO_Pin_8; GPIO_PWMInitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_PWMInitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init( GPIOA, &GPIO_PWMInitStructure ); GPIO_PinRemapConfig(AFIO_PCFR1_TIM1_REMAP_FULLREMAP, ENABLE); time_base_init.TIM_ClockDivision = TIM_CKD_DIV4; time_base_init.TIM_Period = 99; time_base_init.TIM_CounterMode = TIM_CounterMode_Up; time_base_init.TIM_Prescaler = 0; time_base_init.TIM_RepetitionCounter = 0; TIM_TimeBaseInit(TIM1, &time_base_init); timer_output_cfg.TIM_OCMode = TIM_OCMode_PWM1; timer_output_cfg.TIM_OutputState = TIM_OutputState_Enable; timer_output_cfg.TIM_OCPolarity = TIM_OCPolarity_Low; timer_output_cfg.TIM_OCIdleState = 0; // timer_output_cfg.TIM_OCNIdleState = 0; timer_output_cfg.TIM_Pulse = 10; // Если выставлять больше, уровень будет резко меняться, в конечном итоге выставится сплошной уровень по выходу ШИМ. HIGH 0x8F5C LOW 0x47AE // TIM_DMAConfig(TIM1, TIM_DMABase_CCR1, TIM_DMABurstLength_1Transfer); // TIM_DMACmd(TIM1, TIM_DMA_CC1, DISABLE); TIM_OC1Init(TIM1, &timer_output_cfg); TIM_CtrlPWMOutputs(TIM1, ENABLE ); TIM_OC1PreloadConfig( TIM1, TIM_OCPreload_Disable ); TIM_ARRPreloadConfig( TIM1, ENABLE ); TIM_CCxCmd(TIM1, TIM_Channel_1, TIM_CCx_Enable); TIM_ITConfig(TIM1, TIM_IT_CC1, ENABLE); NVIC_EnableIRQ(TIM1_CC_IRQn); TIM_Cmd( TIM1, ENABLE ); }
Вернуться наверх
Реклама
a797945
Заголовок сообщения: Re: CH32V и лента WS2812
Добавлено: Сб май 20, 2023 17:54:16
Карма: 4
Рейтинг сообщений: 80
Зарегистрирован: Вс ноя 01, 2015 09:15:16Сообщений: 445Откуда: 69.Ржев
Рейтинг сообщения: 0
Здесь верно? dma_leds.DMA_PeripheralBaseAddr = (u32)TIM1->DMAADR;
Вернуться наверх
dmitrij999
Заголовок сообщения: Re: CH32V и лента WS2812
Добавлено: Ср май 31, 2023 20:59:37
Зарегистрирован: Ср дек 25, 2019 23:41:33Сообщений: 43
Рейтинг сообщения: 0
Здесь верно? dma_leds.DMA_PeripheralBaseAddr = (u32)TIM1->DMAADR;
Поправил на адрес на CH1CVR для TIM1. Теперь судя по всему, посылки передаются, но не получается выдержать тайминги
Вернуться наверх
Страница 1 из 1
[ Сообщений: 11 ]
Кто сейчас на форуме
Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 20
Вы не можете начинать темы Вы не можете отвечать на сообщения Вы не можете редактировать свои сообщения Вы не можете удалять свои сообщения Вы не можете добавлять вложения