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

Кто любит RISC в жизни, заходим, не стесняемся.
Ответить
Мудрый кот
Сообщения: 1849
Зарегистрирован: Вс дек 25, 2016 08:34:54

Сообщение Dimon456 »

Reflector писал(а):Зачем там memcpy если копировать нужно один 64-х битный элемент массива?
Я не силен в программировании, в этих магических числах, но
Спойлер

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

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

	GPIOA->ODR |= GPIO_Pin_2;

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

	if(isr & WS2812B_DMA_IT_HT)
    {	
	*((uint64_t*)&DMABuffer[0]) = *((uint64_t*)&tablica[pixeld[pixel_cnt].g]);
	*((uint64_t*)&DMABuffer[8]) = *((uint64_t*)&tablica[pixeld[pixel_cnt].r]);
	*((uint64_t*)&DMABuffer[16]) = *((uint64_t*)&tablica[pixeld[pixel_cnt].b]);
    }
    else 
    {	
	*((uint64_t*)&DMABuffer[24]) = *((uint64_t*)&tablica[pixeld[pixel_cnt].g]);
	*((uint64_t*)&DMABuffer[32]) = *((uint64_t*)&tablica[pixeld[pixel_cnt].r]);
	*((uint64_t*)&DMABuffer[40]) = *((uint64_t*)&tablica[pixeld[pixel_cnt].b]);
    }

    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;
}
Единственное, предупреждение warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
На частоте МК 24МГц осциллограф мерит где-то 3мкс, прибор DM90A показывает процент заполнения 10,7%, в общем 11%, не особо, выигрыш 2%.
При добавлении кода
VladislavS писал(а):Попробуй вот такую конструкцию
выигрыш во времени так же есть. С ws_status потом займусь.
Реклама
Поставщик валерьянки для Кота
Сообщения: 2089
Зарегистрирован: Вс июн 19, 2016 09:32:03

Сообщение Reflector »

[uquote="Dimon456",url="/forum/viewtopic.php?p=3918663#p3918663"]На частоте МК 24МГц осциллограф мерит где-то 3мкс[/uquote]
Было 4 us, стало 3 us, уже хорошо. Если еще в таблице и массиве сразу хранить uint64_t, то никакие приведения не потребуются.
Последний раз редактировалось Reflector Вт ноя 03, 2020 22:56:03, всего редактировалось 1 раз.
Реклама
Собутыльник Кота
Аватара пользователя
Сообщения: 2567
Зарегистрирован: Вт май 01, 2018 19:44:47

Сообщение VladislavS »

[uquote="Reflector",url="/forum/viewtopic.php?p=3918674#p3918674"]Было 4 us, стало 3 us, уже хорошо.[/uquote]Ну да, каких-то 2% :)))
Собутыльник Кота
Аватара пользователя
Сообщения: 2567
Зарегистрирован: Вт май 01, 2018 19:44:47

Сообщение VladislavS »

Если pixel_cnt хранить, например, в CNDTR незадействованного DMA-канала, то можно сэкономить на загрузке его адреса.

Ну и, конечно же, выполнение прерывания в SRAM ещё неплохой прирост даст. Я думаю, ваш алгоритм можно в 2 мкс на тактовой 24 МГц утоптать.

Добавлено after 5 hours 43 minutes 28 seconds:
Ещё от компилятора зависит результат. Перенёс эксперименты на F303 на штатной частоте 72 МГц. На IAR для ленты RGBW (4 цвета) прерывание утопталось в 1 мкс. GCC и ARM Compiler 1.1-1.2 мкс на том же коде. Для трёхцветных диодов где-то на 150 нс меньше.
Спойлер

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

void DMA2_Channel3_IRQHandler()
{
  TEST_PIN::set(); __NOP();
  
  uint32_t isr = DMA2->ISR;
  DMA2->IFCR = isr;
  uint32_t tmp = DMA2_Channel2->CNDTR;  // static uint16_t pixel_counter :)
  if(STOP_STATE stop; tmp<STRIP_LEN)   
    dma_pwm_buf[isr&DMA_ISR_HTIF3?0:1] = leds[tmp++];
  else
  { 
    dma_pwm_buf[isr&DMA_ISR_HTIF3?0:1] = stop; 
    tmp++; 
  }
  DMA2_Channel2->CNDTR = tmp;
  
  TEST_PIN::clear();
}

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

//void DMA2_Channel3_IRQHandler()
//{
DMA2_Channel3_IRQHandler:
        PUSH     {R4-R7,LR}
//  TEST_PIN::set(); __NOP();
        LDR.N    R2,??DMA2_Channel3_IRQHandler_0  ;; 0x48000818
        MOVS     R0,#+128
        STR      R0,[R2, #+0]
        Nop      
 
//  uint32_t isr = DMA2->ISR; 
        LDR.N    R3,??DMA2_Channel3_IRQHandler_0+0x4  ;; 0x40020400
        LDR      R1,[R3, #+0]

//  DMA2->IFCR = isr;
        STR      R1,[R3, #+4]

//  uint32_t tmp = DMA2_Channel2->CNDTR;
        LDR      R0,[R3, #+32]

//  if(STOP_STATE stop; tmp<STRIP_LEN)   
        CMP      R0,#+144
        BCS.N    ??DMA2_Channel3_IRQHandler_1

//    dma_pwm_buf[isr&DMA_ISR_HTIF3?0:1] = leds[tmp++];
        LDR.N    R5,??DMA2_Channel3_IRQHandler_0+0x8
        LDR.N    R6,??DMA2_Channel3_IRQHandler_0+0xC
        LDR.N    R7,??DMA2_Channel3_IRQHandler_0+0x10
        ADDS     R4,R0,#+1
        ADD      R0,R5,R0, LSL #+2
        LDRB     LR,[R0, #+1]
        LDRB     R12,[R0, #+2]
        LDRB     R5,[R0, #+3]
        LDRB     R0,[R0, #+0]
        LSLS     R1,R1,#+21
        ITE      MI 
        MOVMI    R1,#+0
        MOVPL    R1,#+32
        ADD      R6,R6,R1
        ADD      R1,R7,R0, LSL #+3
        ADD      LR,R7,LR, LSL #+3
        LDRD     R0,R1,[R1, #+0]
        STRD     R0,R1,[R6, #+0]
        LDRD     R0,R1,[LR, #+0]
        STRD     R0,R1,[R6, #+8]
        ADD      R0,R7,R12, LSL #+3
        LDRD     R0,R1,[R0, #+0]
        STRD     R0,R1,[R6, #+16]
        ADD      R1,R7,R5, LSL #+3
        LDRD     R0,R1,[R1, #+0]
        STRD     R0,R1,[R6, #+24]

//  DMA2_Channel2->CNDTR = tmp;
        STR      R4,[R3, #+32]

//  TEST_PIN::clear();
        MOVS     R0,#+128
        STRH     R0,[R2, #+2]

        POP      {R4-R7,PC}       ;; return
               
//  else
//  { 
//    dma_pwm_buf[isr&DMA_ISR_HTIF3?0:1] = stop; 
??DMA2_Channel3_IRQHandler_1:
        LSLS     R1,R1,#+21
        ITE      MI 
        MOVMI    R1,#+0
        MOVPL    R1,#+32
        LDR.N    R4,??DMA2_Channel3_IRQHandler_0+0xC
        ADD      R1,R4,R1
        MOVS     R6,#+0
        STRD     R6,R6,[R1, #+0]
        STRD     R6,R6,[R1, #+8]
        STRD     R6,R6,[R1, #+16]
        STRD     R6,R6,[R1, #+24]
        
//    tmp++;         
        ADDS     R4,R0,#+1
        
//  }
//  DMA2_Channel2->CNDTR = tmp;        
        STR      R4,[R3, #+32]

//  TEST_PIN::clear();        
        MOVS     R0,#+128
        STRH     R0,[R2, #+2]
        
        POP      {R4-R7,PC}       ;; return
Реклама
Эиком - электронные компоненты и радиодетали
Мудрый кот
Сообщения: 1849
Зарегистрирован: Вс дек 25, 2016 08:34:54

Сообщение Dimon456 »

Столкнулся с непонятностью, мне нужно было знать на какой частоте работает лента ну и таймер.
Из прерывания дма все удалил кроме флага сброса, в буфер дма загрузил WS2812B_PULSE_LOW, и кольцевой запуск без остановки дма.
Сначала проверил на какой частоте работает МК

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

  SystemCoreClockUpdate(); // Вычисление тактовой частоты ядра.

  // -- определение тактирования перефирии
      RCC_ClocksTypeDef clocks;
      RCC_GetClocksFreq(&clocks);
Какую задал, такая и есть = 24МГц.
При значении периода таймера равном 30 частота ШИМ ровно 800кГц(измерено прибором DM90A), LOW=8 HIGH=17, но лента при этой частоте не работает.
Крайние значения таймера для ленты получаются 30 - 160.
В общем частота ШИМ ленты 400кГц значения таймера = 60, а вот это LOW=8 HIGH=17 осталось без изменений.

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

Сообщение VladislavS »

Применяем средства объективного контроля - осциллогляд и напряжометр.
Реклама
ARV
Ум, честь и совесть. И скромность.
Аватара пользователя
Сообщения: 18788
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск

Сообщение ARV »

Чтобы лента работала, в потоке бит обязательно должны быть паузы с длительностью не менее длительности импульса сброса. Я понял так, что дма молотит сплошняком импульсы, вот лента и не реагирует, ждет паузы...
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

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

Сообщение Reflector »

[uquote="ARV",url="/forum/viewtopic.php?p=3919190#p3919190"]Я понял так, что дма молотит сплошняком импульсы, вот лента и не реагирует, ждет паузы...[/uquote]
Как запрограммируют, так и будет работать, может бит передать и остановиться.
Мучитель микросхем
Сообщения: 446
Зарегистрирован: Вс ноя 01, 2015 09:15:16
Откуда: 69.Ржев

Сообщение a797945 »

как диод поймет, что в него влетело это ему лично , а не соседу
Мудрый кот
Сообщения: 1849
Зарегистрирован: Вс дек 25, 2016 08:34:54

Сообщение Dimon456 »

ARV, у меня отрабатывается как одиночный запуск

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

ws281x_send();
так и в цикле

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

    while(1)
    {
    	ws281x_send();
    }
В функции ws281x_send() сначала очищается буфер дма

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

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

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

	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;
в прерывание дма попадаем только тогда когда улетела первая половина буфера, а она равна 0, это и есть сигнал сброс.
То есть ровно 1 светик, при ШИМ 800кГц это 30мкс и +время выполнения функции ws281x_send().
Собутыльник Кота
Аватара пользователя
Сообщения: 2567
Зарегистрирован: Вт май 01, 2018 19:44:47

Сообщение VladislavS »

30 мкс маловато будет.
Мудрый кот
Сообщения: 1849
Зарегистрирован: Вс дек 25, 2016 08:34:54

Сообщение Dimon456 »

VladislavS, что бы не переделывать прерывание дма, добавлю лишний 0 светодиодик в "предварительный буфер дма", а это еще + 30 мкс, итого уже будет 60 мкс, хватит?
Собутыльник Кота
Аватара пользователя
Сообщения: 2567
Зарегистрирован: Вт май 01, 2018 19:44:47

Сообщение VladislavS »

У тебя же DMA на два диода. Если ты буфер перед запуском обнуляешь, то первые два автоматом должны нулями уйти. А 60 уже хватит.
Мудрый кот
Сообщения: 1849
Зарегистрирован: Вс дек 25, 2016 08:34:54

Сообщение Dimon456 »

Да, точно, при первом прерывании дма первая половина буфера уже ушла и пошла вторая, а заполняем первую половину буфера.
Надо в отладчике глянуть.?
А между светиками паузы не надо?
Может так попробовать?
Спойлер

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

	if(isr & WS2812B_DMA_IT_HT)
    {
	*((uint64_t*)&DMABuffer[0]) = *((uint64_t*)&tablica[pixeld[pixel_cnt].g]);
	*((uint64_t*)&DMABuffer[8]) = *((uint64_t*)&tablica[pixeld[pixel_cnt].r]);
	*((uint64_t*)&DMABuffer[16]) = *((uint64_t*)&tablica[pixeld[pixel_cnt].b]);
	DMABuffer[24] = 0;
    }
    else
    {
	*((uint64_t*)&DMABuffer[25]) = *((uint64_t*)&tablica[pixeld[pixel_cnt].g]);
	*((uint64_t*)&DMABuffer[33]) = *((uint64_t*)&tablica[pixeld[pixel_cnt].r]);
	*((uint64_t*)&DMABuffer[41]) = *((uint64_t*)&tablica[pixeld[pixel_cnt].b]);
	DMABuffer[49] = 0;
    }
Собутыльник Кота
Аватара пользователя
Сообщения: 2567
Зарегистрирован: Вт май 01, 2018 19:44:47

Сообщение VladislavS »

А может документацию почитать?
Мудрый кот
Сообщения: 1849
Зарегистрирован: Вс дек 25, 2016 08:34:54

Сообщение Dimon456 »

Документацию на что почитать?
Если есть идеи - говорите, если нет - молчите, а отправлять документацию читать я и сам могу.
Поставщик валерьянки для Кота
Сообщения: 2089
Зарегистрирован: Вс июн 19, 2016 09:32:03

Сообщение Reflector »

[uquote="Dimon456",url="/forum/viewtopic.php?p=3919350#p3919350"]Документацию на что почитать?[/uquote]
Удивительно, но факт, на WS2812B есть документация где, например, говорится какая должна быть минимальная пауза для сброса.
Собутыльник Кота
Аватара пользователя
Сообщения: 2567
Зарегистрирован: Вт май 01, 2018 19:44:47

Сообщение VladislavS »

[uquote="Dimon456",url="/forum/viewtopic.php?p=3919350#p3919350"]Если есть идеи - говорите, если нет - молчите[/uquote]Я свои идеи уже давным давно в коде показал. Так что, иди читай документацию.
Мудрый кот
Сообщения: 1849
Зарегистрирован: Вс дек 25, 2016 08:34:54

Сообщение Dimon456 »

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

Сообщение VladislavS »

[uquote="Dimon456",url="/forum/viewtopic.php?p=3919342#p3919342"]

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

*((uint64_t*)&DMABuffer[25]) = *((uint64_t*)&tablica[pixeld[pixel_cnt].g]);
[/uquote]Верной дорогой к HardFault идёте, товарищи :)
Ответить

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