STM32 новичку в ARM что к чему

Кто любит RISC в жизни, заходим, не стесняемся.
Ответить
Поставщик валерьянки для Кота
Сообщения: 2089
Зарегистрирован: Вс июн 19, 2016 09:32:03

Сообщение Reflector »

[uquote="Dimon456",url="/forum/viewtopic.php?p=3916256#p3916256"]По чему вы свои идеи перекладываете на других? Это же ваша идея, ну покажите, что может этот чип.[/uquote]
Похоже кто-то очень быстро забыл, что сначала ему не понравился сам STM32, т.к. бинарник слишком большой получился, затем ему не понравилось использовать таймер вместо SPI и понять зачем нужен DMA он также поначалу не мог :) Даже буфер уменьшен в 2 раза до 24 байт благодаря моей подсказке, без такого "перекладывания" идей весьма вероятно ты так бы и сидел на SPI отправляющем в цикле по одному биту :)
Реклама
Мудрый кот
Сообщения: 1849
Зарегистрирован: Вс дек 25, 2016 08:34:54

Сообщение Dimon456 »

Reflector писал(а):Даже буфер уменьшен в 2 раза до 24 байт благодаря моей подсказке
да неужели, прямо так с вашей подсказки?
Может цитату свою приведете, ту самую, с вашей подсказкой?

Ну да ладно, речь то не про это, а про дополнительную таблицу, размером в 2 кило.
На сколько вот этот код

Код: Выделить всё

for(uint32_t i=0; i<8; i++)
  dma_pwm_buf[i] = leds[i]; //Тут скрыто идёт преобразование
эффективнее вот этого

Код: Выделить всё

	    uint8_t mask = 128;
	    for (i = 0; i < 8; i++)
	    {
	    	DMABuffer[i] = g & mask ? WS2812B_PULSE_HIGH : WS2812B_PULSE_LOW;	
	        mask >>= 1;
	    }
Реклама
Собутыльник Кота
Аватара пользователя
Сообщения: 2567
Зарегистрирован: Вт май 01, 2018 19:44:47

Сообщение VladislavS »

[uquote="Dimon456",url="/forum/viewtopic.php?p=3916293#p3916293"]На сколько вот этот код

Код: Выделить всё

for(uint32_t i=0; i<8; i++)
  dma_pwm_buf[i] = leds[i]; //Тут скрыто идёт преобразование
эффективнее вот этого

Код: Выделить всё

	    uint8_t mask = 128;
	    for (i = 0; i < 8; i++)
	    {
	    	DMABuffer[i] = g & mask ? WS2812B_PULSE_HIGH : WS2812B_PULSE_LOW;	
	        mask >>= 1;
	    }
[/uquote]Повторение - мать учения!
Поставщик валерьянки для Кота
Сообщения: 2089
Зарегистрирован: Вс июн 19, 2016 09:32:03

Сообщение Reflector »

[uquote="Dimon456",url="/forum/viewtopic.php?p=3916293#p3916293"]да неужели, прямо так с вашей подсказки?
Может цитату свою приведете, ту самую, с вашей подсказкой?[/uquote]
Отчего же не привести... Ты попробовал найденный пример для DMA + таймер и не понравилось, было дрожание и т.д.... В следующем посте ARV жалуется на то, что в том примере нужен буфер целых 48 байт на диод. Следом идет мой пост, где написано:
Берем байт цвета, каждый бит нужно преобразовать в 8-ми битное значение которое потом DMA при копировании дополнит нулем.
И прилагается пример на С++ с буфером типа uint8_t, где еще и при инициализации DMA используются типы DmaSrc::_8b_Inc и DmaDst::_16b.
Реклама
Эиком - электронные компоненты и радиодетали
Мудрый кот
Сообщения: 1849
Зарегистрирован: Вс дек 25, 2016 08:34:54

Сообщение Dimon456 »

Reflector писал(а):И прилагается пример на С++
этот пример, с "иероглифами", был просто упущен, не понятный язык.
За такую помощь большое человеческое СПАСИБО.

VladislavS, теперь надо на С, без всяких ++. Одно смущает, 2 кило на таблицу. Как нибудь потом попробую.
А так, мой алгоритм начинает работать от частоты МК 16МГц.
Реклама
Собутыльник Кота
Аватара пользователя
Сообщения: 2567
Зарегистрирован: Вт май 01, 2018 19:44:47

Сообщение VladislavS »

[uquote="Dimon456",url="/forum/viewtopic.php?p=3916359#p3916359"]VladislavS, теперь надо на С, без всяких ++.[/uquote]Проблемы с даблкликом на ярлыке любимой IDE?
Реклама
Мудрый кот
Сообщения: 1849
Зарегистрирован: Вс дек 25, 2016 08:34:54

Сообщение Dimon456 »

VladislavS писал(а):Проблемы с даблкликом на ярлыке любимой IDE?
Лень, и не вижу смысла.
Текущая частота МК 32 МГц, на этой частоте он успевает просчитывать скрипты, хотя F0 можно гнать до 48 МГц.

Текущую количество рам что я могу использовать это 2330 байт, по чему: стек = 512 байт, буфер куда грузятся скрипты = 512 байт, регистрация функций то же в оперативке находится = 560 байт (это точное число взято из файла map), там маленько осталось не развернуться.

и так что получается, а получается на 254 светика:
- светики 254*5 = 1270 байт
- буфер светиков 254*3 = 762 байт
- буфер дма 24 байта
Сумма = 2310 байта.

Ладно, хватает, может попробую, возможно, лень.
Поставщик валерьянки для Кота
Сообщения: 2089
Зарегистрирован: Вс июн 19, 2016 09:32:03

Сообщение Reflector »

[uquote="Dimon456",url="/forum/viewtopic.php?p=3916977#p3916977"]стек = 512 байт, буфер куда грузятся скрипты = 512 байт, регистрация функций то же в оперативке находится = 560 байт[/uquote]
Первоначально у ARV использовалась mega8 у которой 1КБ RAM, как думаешь сколько там под стек было выделено? И что такое регистрация функций? Какая-то огромная таблица колбеков из HAL? Практически 1КБ потрачен на непонятную фигню, зато массив диодов всего 24 байта :)
Мудрый кот
Сообщения: 1849
Зарегистрирован: Вс дек 25, 2016 08:34:54

Сообщение Dimon456 »

Reflector писал(а):И что такое регистрация функций?
А вот если бы вы в исходный код ARV заглянули, то наверное поняли что я имею ввиду под "регистрацией функций".
Подскажу
Спойлер

Код: Выделить всё

	/* Внедрение моих секций для таблиц */
    __my_tbl_start = __fini_array_end ;
    *(.my_table)
    *(.my_table*)
    KEEP (*(.my_table))
    __my_tbl_end = . ;
    KEEP (SORT(*)(.my_table))
    /* Конец моих секций для таблиц */
Reflector писал(а):Какая-то огромная таблица колбеков из HAL?
HAL не использую, ни куб ни HAL.
Поставщик валерьянки для Кота
Сообщения: 2089
Зарегистрирован: Вс июн 19, 2016 09:32:03

Сообщение Reflector »

[uquote="Dimon456",url=""]А вот если бы вы в исходный код ARV заглянули, то наверное поняли что я имею ввиду под "регистрацией функций".[/uquote]
Насколько я помню когда ARV рассказывал про этот "трюк", то речь шла о таблице во флеше. На AVR адреса 16-ти битные, потратить 280 байт из 1КБ ради удобства в проекте с недостачей RAM было бы не очень разумно. А у тебя таблица в RAM.

Это же оно?
[uquote="ARV",url=""]элементы таблицы объявлены именно с указанием секции. смысл этих телодвижений - создать некий аналог массива во FLASH, элементы которого разбросаны по отдельным модулям проекта - где нужно объявить, там и объявляется, а в итоге все эти разрозненные объвления оказываются в одном массиве.[/uquote]
Мудрый кот
Сообщения: 1849
Зарегистрирован: Вс дек 25, 2016 08:34:54

Сообщение Dimon456 »

Мне не удалось эту таблицу во флеш запихнуть, может вам удастся.
Собутыльник Кота
Аватара пользователя
Сообщения: 2567
Зарегистрирован: Вт май 01, 2018 19:44:47

Сообщение VladislavS »

[uquote="Dimon456",url="/forum/viewtopic.php?p=3916977#p3916977"]Лень, и не вижу смысла.[/uquote]Что и требовалось доказать. Десяток строк С++ кода тупо повторить на Си выливается в целое мероприятие. При том что выигрыш в скорости очевиден - лень перевешивает.
Мудрый кот
Сообщения: 1849
Зарегистрирован: Вс дек 25, 2016 08:34:54

Сообщение Dimon456 »

VladislavS писал(а):Десяток строк С++ кода тупо повторить на Си
и 2 кило флеша на таблицу.
Если и писать, то надо полностью "движок" переписать, загнать его в прерывание дма, что бы получилось что-то вроде псевдо-параллельного процесса.
Мудрый кот
Сообщения: 1849
Зарегистрирован: Вс дек 25, 2016 08:34:54

Сообщение Dimon456 »

VladislavS, кое что я состряпал:
Спойлер

Код: Выделить всё

/* Handles DMA1_Channel1 interrupt request */
void WS2812B_DMA_HANDLER(void)
{	static uint8_t algoritm_cnt = 0;	// счетчик алгоритма
	static uint8_t pixel_cnt = 0;		// счетчик пикселей

    WS2812B_DMA->IFCR = WS2812B_DMA_IT_GL;	// обрабатываем обе половинки

    if(pixel_cnt == PIXEL_CNT+1)			// процедура передачи закончена
    {
    	algoritm_cnt=10;
    }

    switch (algoritm_cnt) {
    	case 0:	algoritm_cnt=1; break;	// формирование сигнала сброс
    	case 1:	algoritm_cnt=2; break;
    	case 2:	algoritm_cnt=3; break;
    	case 3:	algoritm_cnt=4; break;
    	case 4:	algoritm_cnt=5; 		// грузим первую половину буфера
    			memcpy(&DMABuffer[0], &tablica[pixeld[pixel_cnt].g], 8);	// грузим 8 байт из таблицы
    			memcpy(&DMABuffer[8], &tablica[pixeld[pixel_cnt].r], 4);	// грузим первые 4 байта из таблицы
    							break;
    	case 5:	algoritm_cnt=4;			// грузим вторую половину буфера
    			memcpy(&DMABuffer[12], (&tablica[pixeld[pixel_cnt].r])+4, 4);	// грузим вторые 4 байта из таблицы
    			memcpy(&DMABuffer[16], &tablica[pixeld[pixel_cnt].b], 8);	// грузим 8 байт из таблицы
    			pixel_cnt++;			// увеличить счетчик пикселей
    							break;
    	default: pixel_cnt=0; algoritm_cnt=0; ws_status = 0;
    	// Disable Timer	выключение канала
    	WS2812B_TIM->CR1 &= (uint16_t)(~((uint16_t)TIM_CR1_CEN));
    	// DMA1 Channel1 disable
    	WS2812B_DMA_CHANNEL->CCR &= (uint16_t)(~DMA_CCR1_EN);
    							break;
    }

}

void ws281x_send(void)
{
	if(ws_status) return;	// пока алгоритм не отработал пропускаем

	memset(DMABuffer, 0, (sizeof(DMABuffer))); // очистить буфер дма для сигнала сброс

	// копирование карты пикселей в предварительный буфер дма
	for (uint8_t tp = 0; tp < PIXEL_CNT; tp++) {

		uint16_t bright = (pixels[tp].bright + 1);

		pixeld[tp].b = ((pixels[tp].b * bright)>>8);
		pixeld[tp].g = ((pixels[tp].g * bright)>>8);
		pixeld[tp].r = ((pixels[tp].r * bright)>>8);
	}

	/* бит сброса алгоритма */
	ws_status = 1;

	// запуск канала
	WS2812B_DMA_CHANNEL->CNDTR = sizeof(DMABuffer);
	// DMA1 Channel1 enable
	WS2812B_DMA_CHANNEL->CCR |= DMA_CCR1_EN;
	// clear counter for clean start
	WS2812B_TIM->CNT = 0;
	WS2812B_TIM->CCR1 = 0;
	// Enable Timer
	WS2812B_TIM->CR1 |= TIM_CR1_CEN;

}
Код работает, но не так как хотелось, мой старый вариант лучше работает.
Какие будут соображения по поводу оптимизации, короче, кто что подскажет?
Собутыльник Кота
Аватара пользователя
Сообщения: 2567
Зарегистрирован: Вт май 01, 2018 19:44:47

Сообщение VladislavS »

К чему весь этот судорог? Берём два буфера для dma. В прерывании dma "пол-передачи" копируем текущий диод в первый буфер, а в прерывании "конец передачи" во второй буфер. Если диод++ больше длины ленты, то вместо диода копируем в буфер состояние стоп. Сам счётчик можно не останавливать, он 32-битный и переполнится очень не скоро.

Для фонового процесса: если счётчик превысил длину ленты на 2, то можно следующий кадр запускать обнулением счётчика. Массив диодов при этом можно либо обновлять перед запуском, либо подсовывать адрес предварительно заполненного в фоне второго массива.

Добавлено after 1 hour 39 minutes 12 seconds:
Смотри как просто и красиво это на плюсах выглядит. Для начала чуть поправим буфер dma, чтобы он мог принимать состояние STOP.

Код: Выделить всё

struct STOP_STATE {};

struct PWM_RGB_BUF
{
  uint64_t g;
  uint64_t r;
  uint64_t b;

  inline PWM_RGB_BUF& operator=(RGB rgb)
  {
    this->g = color2pwm(rgb.g);
    this->r = color2pwm(rgb.r);   
    this->b = color2pwm(rgb.b);
    return *this; 
  } 
 
  inline PWM_RGB_BUF& operator=(STOP_STATE stst)
  {
    this->g = 0;
    this->r = 0;   
    this->b = 0;
    return *this; 
  } 
};
Собственно прерывание DMA
Добавлено after 36 minutes 13 seconds:
Немного оптимизировал код в прерывании. Работать напрямую с volatile counter дорого, так же как и с DMA1->ISR. С копией оптимальнее получается. Берите на заметку!

Код: Выделить всё

void DMA1_Channel1_IRQHandler()
{
  uint32_t isr = DMA1->ISR;
  uint32_t tmp = counter;
  DMA1->IFCR = DMA_IFCR_CHTIF1 | DMA_IFCR_CTCIF1;
  if(STOP_STATE stop; tmp<STRIP_LEN) 
    dma_pwm_buf[isr&DMA_ISR_HTIF1?0:1] = leds[tmp]; 
  else 
    dma_pwm_buf[isr&DMA_ISR_HTIF1?0:1] = stop;
  counter=tmp+1;
}
Листинг. Там я руками команды и комментарии переставлял для наглядности. Реально компилятор немного не так сделал, наверняка для скорости.
Спойлер

Код: Выделить всё

//extern "C" void DMA1_Channel1_IRQHandler()
//{
DMA1_Channel1_IRQHandler:
        PUSH     {R4-R7}
//  uint32_t isr = DMA1->ISR;
        LDR.N    R1,??DataTable2  ;; 0x40020000
        LDR      R0,[R1, #+0]
//  uint32_t tmp=counter;
        LDR.N    R2,??DataTable2_1
        LDR      R3,[R2, #+300]
//  DMA1->IFCR = DMA_IFCR_CHTIF1 | DMA_IFCR_CTCIF1;
        MOVS     R4,#+6
        STR      R4,[R1, #+4]
//  if(STOP_STATE stop; tmp<STRIP_LEN) 
        CMP      R3,#+100
        BCS.N    ??DMA1_Channel1_IRQHandler_0
//    dma_pwm_buf[isr&DMA_ISR_HTIF1?0:1] = leds[tmp]; 
        LSLS     R0,R0,#+29
        ADD      R1,R3,R3, LSL #+1
        ITE      MI 
        MOVMI    R0,#+0
        MOVPL    R0,#+24
        ADD      R1,R2,R1
        ADD      R5,R2,#+304
        ADD      R5,R5,R0
        LDRB     R6,[R1, #+1]
        LDRB     R4,[R1, #+2]
        LDRB     R0,[R1, #+0]
        LDR.N    R7,??DataTable2_2
        ADD      R1,R7,R0, LSL #+3
        ADD      R6,R7,R6, LSL #+3
        LDRD     R0,R1,[R1, #+0]
        STRD     R0,R1,[R5, #+0]
        LDRD     R0,R1,[R6, #+0]
        STRD     R0,R1,[R5, #+8]
        ADD      R0,R7,R4, LSL #+3
        LDRD     R0,R1,[R0, #+0]
        STRD     R0,R1,[R5, #+16]
//  counter=tmp+1;
        ADDS     R3,R3,#+1
        STR      R3,[R2, #+300]
        POP      {R4-R7}
        BX       LR               ;; return
//  else 
//    dma_pwm_buf[isr&DMA_ISR_HTIF1?0:1] = stop;
??DMA1_Channel1_IRQHandler_0:
        LSLS     R0,R0,#+29
        ITE      MI 
        MOVMI    R0,#+0
        MOVPL    R0,#+24
        ADD      R1,R2,#+304
        ADD      R0,R1,R0
        MOVS     R4,#+0
        STRD     R4,R4,[R0, #+0]
        STRD     R4,R4,[R0, #+8]
        STRD     R4,R4,[R0, #+16]
//  counter=tmp+1;
        ADDS     R3,R3,#+1
        STR      R3,[R2, #+300]
        POP      {R4-R7}
        BX       LR               ;; return
//}

Собутыльник Кота
Аватара пользователя
Сообщения: 2567
Зарегистрирован: Вт май 01, 2018 19:44:47

Сообщение VladislavS »

Запустил на железе. На 64 МГц время выполнения прерывания (дергаю ногой и смотрю на осциллографе) коло 1,5 мкc (5% времени) во время паузы 0.7 мкс (2,5% времени). Это уже с гамма-коррекцией "на лету".

Опустил тактовую процессора до 4 МГц. Успевает, гад.
Мудрый кот
Сообщения: 1849
Зарегистрирован: Вс дек 25, 2016 08:34:54

Сообщение Dimon456 »

Изменил код, буфер сделал 48 байт, что бы пиксель влазил.
Померил с разными вариантами, также осциллографом, на частоте 24МГц:
Вариант 1, 4mks
Спойлер

Код: Выделить всё

/* Handles DMA1_Channel1 interrupt request */
void WS2812B_DMA_HANDLER(void)
{	static uint8_t pixel_cnt = 0;		// счетчик пикселей

	GPIOA->ODR |= GPIO_Pin_2;

    if(WS2812B_DMA->ISR & WS2812B_DMA_IT_HT)
    {	WS2812B_DMA->IFCR = WS2812B_DMA_IT_HT;

    memcpy(&DMABuffer[0], &tablica[pixeld[pixel_cnt].g], 8);	
	memcpy(&DMABuffer[8], &tablica[pixeld[pixel_cnt].r], 8);	
	memcpy(&DMABuffer[16], &tablica[pixeld[pixel_cnt].b], 8);	
    }
    else if(WS2812B_DMA->ISR & WS2812B_DMA_IT_TC)
    {	WS2812B_DMA->IFCR = WS2812B_DMA_IT_TC;

	memcpy(&DMABuffer[24], &tablica[pixeld[pixel_cnt].g], 8);	
	memcpy(&DMABuffer[32], &tablica[pixeld[pixel_cnt].r], 8);	
	memcpy(&DMABuffer[40], &tablica[pixeld[pixel_cnt].b], 8);	
    }

    if(pixel_cnt++ == (PIXEL_CNT+1))			// процедура передачи закончена
    {
    	pixel_cnt=0; ws_status = 0;
    	// Disable Timer	выключение канала
    	WS2812B_TIM->CR1 &= (uint16_t)(~((uint16_t)TIM_CR1_CEN));
    	// DMA1 Channel1 disable
    	WS2812B_DMA_CHANNEL->CCR &= (uint16_t)(~DMA_CCR1_EN);
    	// Clear DMA1_Channel1 interrupts
    	WS2812B_DMA->IFCR = WS2812B_DMA_IT_HT;
    	WS2812B_DMA->IFCR = WS2812B_DMA_IT_TC;
    }

    GPIOA->ODR &= ~GPIO_Pin_2;
}
Вариант 2, 6mks
Спойлер

Код: Выделить всё

/* Handles DMA1_Channel1 interrupt request */
void WS2812B_DMA_HANDLER(void)
{	static uint8_t pixel_cnt = 0;		// счетчик пикселей

	GPIOA->ODR |= GPIO_Pin_2;

    if(WS2812B_DMA->ISR & WS2812B_DMA_IT_HT)
    {	WS2812B_DMA->IFCR = WS2812B_DMA_IT_HT;
 	 	
    	DMABuffer[0] = tablica[pixeld[pixel_cnt].g][0];
		DMABuffer[1] = tablica[pixeld[pixel_cnt].g][1];
		DMABuffer[2] = tablica[pixeld[pixel_cnt].g][2];
		DMABuffer[3] = tablica[pixeld[pixel_cnt].g][3];
		DMABuffer[4] = tablica[pixeld[pixel_cnt].g][4];
		DMABuffer[5] = tablica[pixeld[pixel_cnt].g][5];
		DMABuffer[6] = tablica[pixeld[pixel_cnt].g][6];
		DMABuffer[7] = tablica[pixeld[pixel_cnt].g][7];
		DMABuffer[8] = tablica[pixeld[pixel_cnt].r][0];
		DMABuffer[9] = tablica[pixeld[pixel_cnt].r][1];
		DMABuffer[10] = tablica[pixeld[pixel_cnt].r][2];
		DMABuffer[11] = tablica[pixeld[pixel_cnt].r][3];
		DMABuffer[12] = tablica[pixeld[pixel_cnt].r][4];
		DMABuffer[13] = tablica[pixeld[pixel_cnt].r][5];
		DMABuffer[14] = tablica[pixeld[pixel_cnt].r][6];
		DMABuffer[15] = tablica[pixeld[pixel_cnt].r][7];
		DMABuffer[16] = tablica[pixeld[pixel_cnt].b][0];
		DMABuffer[17] = tablica[pixeld[pixel_cnt].b][1];
		DMABuffer[18] = tablica[pixeld[pixel_cnt].b][2];
		DMABuffer[19] = tablica[pixeld[pixel_cnt].b][3];
		DMABuffer[20] = tablica[pixeld[pixel_cnt].b][4];
		DMABuffer[21] = tablica[pixeld[pixel_cnt].b][5];
		DMABuffer[22] = tablica[pixeld[pixel_cnt].b][6];
		DMABuffer[23] = tablica[pixeld[pixel_cnt].b][7];

    }
    else if(WS2812B_DMA->ISR & WS2812B_DMA_IT_TC)
    {	WS2812B_DMA->IFCR = WS2812B_DMA_IT_TC;

    DMABuffer[24] = tablica[pixeld[pixel_cnt].g][0];
	DMABuffer[25] = tablica[pixeld[pixel_cnt].g][1];
	DMABuffer[26] = tablica[pixeld[pixel_cnt].g][2];
	DMABuffer[27] = tablica[pixeld[pixel_cnt].g][3];
	DMABuffer[28] = tablica[pixeld[pixel_cnt].g][4];
	DMABuffer[29] = tablica[pixeld[pixel_cnt].g][5];
	DMABuffer[30] = tablica[pixeld[pixel_cnt].g][6];
	DMABuffer[31] = tablica[pixeld[pixel_cnt].g][7];
	DMABuffer[32] = tablica[pixeld[pixel_cnt].r][0];
	DMABuffer[33] = tablica[pixeld[pixel_cnt].r][1];
	DMABuffer[34] = tablica[pixeld[pixel_cnt].r][2];
	DMABuffer[35] = tablica[pixeld[pixel_cnt].r][3];
	DMABuffer[36] = tablica[pixeld[pixel_cnt].r][4];
	DMABuffer[37] = tablica[pixeld[pixel_cnt].r][5];
	DMABuffer[38] = tablica[pixeld[pixel_cnt].r][6];
	DMABuffer[39] = tablica[pixeld[pixel_cnt].r][7];
	DMABuffer[40] = tablica[pixeld[pixel_cnt].b][0];
	DMABuffer[41] = tablica[pixeld[pixel_cnt].b][1];
	DMABuffer[42] = tablica[pixeld[pixel_cnt].b][2];
	DMABuffer[43] = tablica[pixeld[pixel_cnt].b][3];
	DMABuffer[44] = tablica[pixeld[pixel_cnt].b][4];
	DMABuffer[45] = tablica[pixeld[pixel_cnt].b][5];
	DMABuffer[46] = tablica[pixeld[pixel_cnt].b][6];
	DMABuffer[47] = tablica[pixeld[pixel_cnt].b][7];

    }

    if(pixel_cnt++ == (PIXEL_CNT+1))			// процедура передачи закончена
    {
    	pixel_cnt=0; ws_status = 0;
    	// Disable Timer	выключение канала
    	WS2812B_TIM->CR1 &= (uint16_t)(~((uint16_t)TIM_CR1_CEN));
    	// DMA1 Channel1 disable
    	WS2812B_DMA_CHANNEL->CCR &= (uint16_t)(~DMA_CCR1_EN);
    	// Clear DMA1_Channel1 interrupts
    	WS2812B_DMA->IFCR = WS2812B_DMA_IT_HT;
    	WS2812B_DMA->IFCR = WS2812B_DMA_IT_TC;
    }

    GPIOA->ODR &= ~GPIO_Pin_2;
}
Вариант 3, 10mks
Спойлер

Код: Выделить всё

/* Handles DMA1_Channel1 interrupt request */
void WS2812B_DMA_HANDLER(void)
{	static uint8_t pixel_cnt = 0;		// счетчик пикселей

	GPIOA->ODR |= GPIO_Pin_2;

    if(WS2812B_DMA->ISR & WS2812B_DMA_IT_HT)
    {	WS2812B_DMA->IFCR = WS2812B_DMA_IT_HT;

    for (uint8_t i = 0; i < 8; i++)
	{
		DMABuffer[i] = tablica[pixeld[pixel_cnt].g][i];	
	}
    for (uint8_t i = 8; i < 16; i++)
    {
    	DMABuffer[i] = tablica[pixeld[pixel_cnt].r][i-8];	

    }
	for (uint8_t i = 16; i < 24; i++)
	{
		DMABuffer[i] = tablica[pixeld[pixel_cnt].b][i-16];	
	}

    }
    else if(WS2812B_DMA->ISR & WS2812B_DMA_IT_TC)
    {	WS2812B_DMA->IFCR = WS2812B_DMA_IT_TC;

	for (uint8_t i = 24; i < 32; i++)
	{
		DMABuffer[i] = tablica[pixeld[pixel_cnt].g][i-24];	
	}
    for (uint8_t i = 32; i < 40; i++)
    {
    	DMABuffer[i] = tablica[pixeld[pixel_cnt].r][i-32];	

    }
	for (uint8_t i = 40; i < 48; i++)
	{
		DMABuffer[i] = tablica[pixeld[pixel_cnt].b][i-40];	
	}

    }

    if(pixel_cnt++ == (PIXEL_CNT+1))			// процедура передачи закончена
    {
    	pixel_cnt=0; ws_status = 0;
    	// Disable Timer	выключение канала
    	WS2812B_TIM->CR1 &= (uint16_t)(~((uint16_t)TIM_CR1_CEN));
    	// DMA1 Channel1 disable
    	WS2812B_DMA_CHANNEL->CCR &= (uint16_t)(~DMA_CCR1_EN);
    	// Clear DMA1_Channel1 interrupts
    	WS2812B_DMA->IFCR = WS2812B_DMA_IT_HT;
    	WS2812B_DMA->IFCR = WS2812B_DMA_IT_TC;
    }

    GPIOA->ODR &= ~GPIO_Pin_2;
}
И вариант 4, без таблицы, 14mks
Спойлер

Код: Выделить всё

/* Handles DMA1_Channel1 interrupt request */
void WS2812B_DMA_HANDLER(void)
{	static uint8_t pixel_cnt = 0;		// счетчик пикселей

	GPIOA->ODR |= GPIO_Pin_2;

    if(WS2812B_DMA->ISR & WS2812B_DMA_IT_HT)
    {	WS2812B_DMA->IFCR = WS2812B_DMA_IT_HT;

    uint8_t mask = 128;
    for (uint8_t i = 0; i < 8; i++)
    {
    	DMABuffer[i] = pixeld[pixel_cnt].g & mask ? WS2812B_PULSE_HIGH : WS2812B_PULSE_LOW;	
        mask >>= 1;
    }
    mask = 128;
    for (uint8_t i = 8; i < 16; i++)
    {
    	DMABuffer[i] = pixeld[pixel_cnt].r & mask ? WS2812B_PULSE_HIGH : WS2812B_PULSE_LOW;	
        mask >>= 1;
    }
    mask = 128;
    for (uint8_t i = 16; i < 24; i++)
    {
    	DMABuffer[i] = pixeld[pixel_cnt].b & mask ? WS2812B_PULSE_HIGH : WS2812B_PULSE_LOW;	
        mask >>= 1;
    }

    }
    else if(WS2812B_DMA->ISR & WS2812B_DMA_IT_TC)
    {	WS2812B_DMA->IFCR = WS2812B_DMA_IT_TC;

    uint8_t mask = 128;
    for (uint8_t i = 24; i < 32; i++)
    {
    	DMABuffer[i] = pixeld[pixel_cnt].g & mask ? WS2812B_PULSE_HIGH : WS2812B_PULSE_LOW;	
        mask >>= 1;
    }
    mask = 128;
    for (uint8_t i = 32; i < 40; i++)
    {
    	DMABuffer[i] = pixeld[pixel_cnt].r & mask ? WS2812B_PULSE_HIGH : WS2812B_PULSE_LOW;	
        mask >>= 1;
    }
    mask = 128;
    for (uint8_t i = 40; i < 48; i++)
    {
    	DMABuffer[i] = pixeld[pixel_cnt].b & mask ? WS2812B_PULSE_HIGH : WS2812B_PULSE_LOW;	
        mask >>= 1;
    }

    }

    if(pixel_cnt++ == (PIXEL_CNT+1))			// процедура передачи закончена
    {
    	pixel_cnt=0; ws_status = 0;
    	// Disable Timer	выключение канала
    	WS2812B_TIM->CR1 &= (uint16_t)(~((uint16_t)TIM_CR1_CEN));
    	// DMA1 Channel1 disable
    	WS2812B_DMA_CHANNEL->CCR &= (uint16_t)(~DMA_CCR1_EN);
    	// Clear DMA1_Channel1 interrupts
    	WS2812B_DMA->IFCR = WS2812B_DMA_IT_HT;
    	WS2812B_DMA->IFCR = WS2812B_DMA_IT_TC;
    }

    GPIOA->ODR &= ~GPIO_Pin_2;
}
На передачу 1 светика тратится где-то 30мкс, так что в самом худшем варианте получается 47% времени, в самом лучшем 13%.
Замерил вариант 1 частоту прибором DM90A = 31кГц, процент заполнения 13%, так что осциллографом точно померил.
Могу замерить для 64МГц, если надо, если F100 раскочегарится, по моему этот чип разгоняется только до 56МГц?
Собутыльник Кота
Аватара пользователя
Сообщения: 2567
Зарегистрирован: Вт май 01, 2018 19:44:47

Сообщение VladislavS »

Попробуй вот такую конструкцию, должно быстрее стать

Код: Выделить всё

uint32_t isr = DMA1->ISR;
DMA1->IFCR = isr;

if(isr & DMA_ISR_HTIF1)
{

}
else
{

}
Поставщик валерьянки для Кота
Сообщения: 2089
Зарегистрирован: Вс июн 19, 2016 09:32:03

Сообщение Reflector »

[uquote="Dimon456",url="/forum/viewtopic.php?p=3918465#p3918465"]Вариант 1, 4mks[/uquote]
Зачем там memcpy если копировать нужно один 64-х битный элемент массива? :)
Собутыльник Кота
Аватара пользователя
Сообщения: 2567
Зарегистрирован: Вт май 01, 2018 19:44:47

Сообщение VladislavS »

На разных ядрах, кстати, будет разный результат. Я попался на том, что листинг смотрел на Cortex-M4, а замеры скорости делал на Cortex-M0+ и результаты не бились.

ЗЫ: В вашем варианте ws_status тоже можно выкинуть. Наличие TIM_CR1_CEN можно использовать как флаг.
Ответить

Вернуться в «ARM»