jcxz 239 3 октября, 2023 Опубликовано 3 октября, 2023 · Жалоба 2 часа назад, kan35 сказал: И как уже сказали, сидеть в прерывании 30мкс - не правильно. Не надо повторять чужой вздор. 2 часа назад, kan35 сказал: Жизнь полна сюрпризов, согласен, но я не встречал еще такой задачи, где бы обязательно нарушался базовый тезис о том, что прерывание должно быть как можно короче. Детям в начальной школе тоже объясняют, что "делить на ноль нельзя". И только в старших классах (или ВУЗе?) они узнают, что всё-таки можно. Если вы когда-нибудь откроете и почитаете мануал на ядро Cortex-M, то с удивлением обнаружите, что его разработчики заранее заложили в него возможность работать всегда в прерывании. Т.е. - вообще 100% времени находиться в прерывании. И это - нормальный режим работы ядра. Не то что какие-то мкс, а часы может там сидеть. И это - норма. 2 часа назад, kan35 сказал: Поэтому перетаскивайте всё в поток и не мудрите. А ничего, что у автора могут быть другие менее приоритетные ISR? Не задумывались? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
amaora 24 11 октября, 2023 Опубликовано 11 октября, 2023 (изменено) · Жалоба Все получается, велосипед едет. Оказалось необходимо использовать DMA2 (и соответственно TIM8) для доступа к AHB на которой GPIO. Перезапуск передачи (вызов AS5047_get_EP) занимает около ~100 тактов на F4. Spoiler int AS5047_get_EP() { int EP; if (priv_AS5047.rxbuf[1] & 0x4000U) { /* TODO */ } EP = (int) (priv_AS5047.rxbuf[1] & 0x3FFFU); priv_AS5047.txbuf[0] = 0xFFFFU; priv_AS5047.txbuf[1] = 0xC000U; SPI_transfer_dma(HW_SPI_EXT_ID, priv_AS5047.txbuf, priv_AS5047.rxbuf, 2); return EP; } ... void SPI_transfer_dma(int bus, const uint16_t *txbuf, uint16_t *rxbuf, int len) { DMA2_Stream4->CR &= ~DMA_SxCR_EN; DMA2_Stream3->CR &= ~DMA_SxCR_EN; #ifdef STM32F7 /* Clean D-Cache on TXBUF. * */ SCB_CleanDCacheByAddr((void *) txbuf, len * sizeof(uint16_t)); /* Invalidate D-Cache on RXBUF. * */ SCB_InvalidateDCacheByAddr((void *) rxbuf, len * sizeof(uint16_t)); #endif /* STM32F7 */ DMA2_Stream4->NDTR = len; DMA2_Stream3->NDTR = len; DMA2_Stream4->M0AR = (uint32_t) rxbuf; DMA2_Stream3->M0AR = (uint32_t) txbuf; DMA2->LIFCR = DMA_LIFCR_CTCIF3 | DMA_LIFCR_CHTIF3 | DMA_LIFCR_CTEIF3 | DMA_LIFCR_CFEIF3; DMA2->HIFCR = DMA_HIFCR_CTCIF4 | DMA_HIFCR_CHTIF4 | DMA_HIFCR_CTEIF4 | DMA_HIFCR_CFEIF4; DMA2_Stream4->CR |= DMA_SxCR_EN; DMA2_Stream3->CR |= DMA_SxCR_EN; TIM8->CNT = 0; TIM8->RCR = len - 1U; TIM8->CR1 |= TIM_CR1_CEN; } void SPI_startup(int bus, int freq, int mode) { ... if (mode & SPI_DMA) { RCC->AHB1ENR |= RCC_AHB1ENR_DMA2EN; RCC->APB2ENR |= RCC_APB2ENR_TIM8EN; TIM8->CR1 = TIM_CR1_OPM; TIM8->CR2 = 0; TIM8->SMCR = 0; TIM8->DIER = TIM_DIER_CC4DE | TIM_DIER_CC3DE | TIM_DIER_CC2DE | TIM_DIER_CC1DE; TIM8->CCMR1 = 0; TIM8->CCMR2 = 0; TIM8->CCER = 0; TIM8->PSC = CLOCK_TIM8_HZ / 2U / priv_SPI[bus].clock - 1U; TIM8->ARR = 44U; TIM8->CCR1 = 2U; /* NSS = 0 */ TIM8->CCR2 = 5U; /* DR = txbuf */ TIM8->CCR3 = 42U; /* rxbuf = DR */ TIM8->CCR4 = 42U; /* NSS = 1 */ /* DMA on TIM8_CH3. * */ DMA2_Stream4->CR = (7U << DMA_SxCR_CHSEL_Pos) | DMA_SxCR_PL_1 | (1U << DMA_SxCR_MSIZE_Pos) | (1U << DMA_SxCR_PSIZE_Pos) | DMA_SxCR_MINC; DMA2_Stream4->PAR = (uint32_t) &priv_SPI[bus].SPI->DR; DMA2_Stream4->FCR = DMA_SxFCR_DMDIS; /* DMA on TIM8_CH2. * */ DMA2_Stream3->CR = (7U << DMA_SxCR_CHSEL_Pos) | DMA_SxCR_PL_1 | (1U << DMA_SxCR_MSIZE_Pos) | (1U << DMA_SxCR_PSIZE_Pos) | DMA_SxCR_MINC | DMA_SxCR_DIR_0; DMA2_Stream3->PAR = (uint32_t) &priv_SPI[bus].SPI->DR; DMA2_Stream3->FCR = DMA_SxFCR_DMDIS; #define XGPIO_GET_BSRR(xGPIO) (GPIOA_BASE + 0x0400U * XGPIO_GET_PORT(xGPIO) + 0x18U) /* DMA on TIM8_CH1. * */ DMA2_Stream2->CR = (7U << DMA_SxCR_CHSEL_Pos) | DMA_SxCR_PL_1 | (2U << DMA_SxCR_MSIZE_Pos) | (2U << DMA_SxCR_PSIZE_Pos) | DMA_SxCR_DIR_0 | DMA_SxCR_CIRC; DMA2_Stream2->NDTR = 1U; DMA2_Stream2->PAR = (uint32_t) XGPIO_GET_BSRR(priv_SPI[bus].gpio_NSS); DMA2_Stream2->M0AR = (uint32_t) &priv_SPI[bus].gpio_rst; DMA2_Stream2->FCR = DMA_SxFCR_DMDIS; /* DMA on TIM8_CH4. * */ DMA2_Stream7->CR = (7U << DMA_SxCR_CHSEL_Pos) | DMA_SxCR_PL_1 | (2U << DMA_SxCR_MSIZE_Pos) | (2U << DMA_SxCR_PSIZE_Pos) | DMA_SxCR_DIR_0 | DMA_SxCR_CIRC; DMA2_Stream7->NDTR = 1U; DMA2_Stream7->PAR = (uint32_t) XGPIO_GET_BSRR(priv_SPI[bus].gpio_NSS); DMA2_Stream7->M0AR = (uint32_t) &priv_SPI[bus].gpio_set; DMA2_Stream7->FCR = DMA_SxFCR_DMDIS; N = XGPIO_GET_N(priv_SPI[bus].gpio_NSS); priv_SPI[bus].gpio_rst = (1U << (N + 16)); priv_SPI[bus].gpio_set = (1U << N); #ifdef STM32F7 /* D-Cache Clean. * */ SCB->DCCMVAC = (uint32_t) &priv_SPI[bus].gpio_rst; SCB->DCCMVAC = (uint32_t) &priv_SPI[bus].gpio_set; __DSB(); __ISB(); #endif /* STM32F7 */ DMA2_Stream2->CR |= DMA_SxCR_EN; DMA2_Stream7->CR |= DMA_SxCR_EN; } /* Enable SPI. * */ priv_SPI[bus].SPI->CR1 |= SPI_CR1_SPE; } Добавка: Похоже я как-то криво работаю с кэшами в F7 и не могу найти подробную информацию (ни у ST ни у ARM), в частности по регистрам DCCIMVAC и подобным, можно ли туда невыровненный адрес писать или нет? Изменено 11 октября, 2023 пользователем amaora Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 183 11 октября, 2023 Опубликовано 11 октября, 2023 · Жалоба Что-то не понятно, для чего в void SPI_transfer_dma(int bus, const uint16_t *txbuf, uint16_t *rxbuf, int len) строчка SCB_InvalidateDCacheByAddr((void *) rxbuf, len * sizeof(uint16_t)); При вызове и выходе из неблокирующей SPI_transfer_dma() хотите забрать в rxbuf принятые данные предыдущей транзакции? rxbuf, txbuf - сами массивы расположены в кэшируемом регионе ОЗУ? По кэш-строке выровнили адрес размещения? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
amaora 24 11 октября, 2023 Опубликовано 11 октября, 2023 · Жалоба 12 minutes ago, Arlleex said: При вызове и выходе из неблокирующей SPI_transfer_dma() хотите забрать в rxbuf принятые данные предыдущей транзакции? Инвалидация нужна чтобы прочитать rxbuf из памяти а не старые значения из кэша. Да, забираю результат предыдущей транзакции. В моем случае действительно проще объявить все dma данные выровненными. У меня вся RAM кэшируется, MPU не настраивал. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
haker_fox 61 12 октября, 2023 Опубликовано 12 октября, 2023 · Жалоба On 10/3/2023 at 5:20 PM, jcxz said: Не то что какие-то мкс, а часы может там сидеть. И это - норма. Кстати, мне вот подумалось: а чем это ядро так уникально в этом плане? В принципе, можно взять любую восьмибитку (avr, pic, что угодно) и тоже заставить код выполняться в обработчике хоть несколько часов. При этом код главного цикла не получит управления на любой из озученных архитектур. Или что Вы имели в виду?💗 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Forger 26 12 октября, 2023 Опубликовано 12 октября, 2023 · Жалоба 1 hour ago, haker_fox said: взять любую восьмибитку (avr, pic, что угодно) У них обычно очень простой контроллер прерываний - пока одно прерывание не закончиться, остальные будут молча ждать своей очереди, т.е. нет "вытеснения". On 10/3/2023 at 12:20 PM, jcxz said: часы может там сидеть. И это - норма это только если в проекте вообще не используется RTOS или ее подобие т.е. в таких простых проектах, в таких обычно в конце main() ставят бесконечный цикл и тогда действительно можно хоть вечно "жить" в прерывании Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
haker_fox 61 12 октября, 2023 Опубликовано 12 октября, 2023 · Жалоба 23 minutes ago, Forger said: У них обычно очень простой контроллер прерываний - пока одно прерывание не закончиться, остальные будут молча ждать своей очереди, т.е. нет "вытеснения". Речь у уважаемого @jcxz шла о прерывании, т.е. там было единственное число. Если тут нет опечатки, то вот это и стало интересным. Если речь о множественном числе, т.е. о прерываниях, то тут, конечно же, другие ядра с их контроллерами прерываний несколько проигрывают. Теоретически можно сказать, что Cortex-Mx всегда работает в прерываних, где главный цикл (пусть даже с ОСРВ) - прерывание, только нулевого уровня. "Под ним" ничего нет... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 183 12 октября, 2023 Опубликовано 12 октября, 2023 · Жалоба 9 часов назад, amaora сказал: В моем случае действительно проще объявить все dma данные выровненными. Вообще, по-хорошему, так нужно делать всегда, т.к. постоянно в каждом месте применения флуша/инвалидации думать, а какие же еще там рядом переменные в той же строке кэша лежат - занятие неблагодарное, так не делают 38 минут назад, haker_fox сказал: Речь у уважаемого @jcxz шла о прерывании, т.е. там было единственное число. Если тут нет опечатки, то вот это и стало интересным. jcxz имел в виду событийный/энергосберегающий режим работы ядра - когда по выходу из обработчика ядро засыпает, а пробудить его может очередной запрос на прерывание, сгенерированный каким-то событием. Вот с точки зрения МК это и будет жизнью внутри прерывания. Цитата Теоретически можно сказать, что Cortex-Mx всегда работает в прерываних, где главный цикл (пусть даже с ОСРВ) - прерывание, только нулевого уровня. "Под ним" ничего нет... У Cortex-M есть такое понятие как приоритет выполнения (execution priority), он зависит от режима CPU (thread/handler). Технически это позволило реализовать поток инструкций для обработчика прерывания неотличимым от инструкций основного потока (в отличие от того же AVR с их ret/reti). Но вряд ли тут можно провести прямую параллельную мысль, что ядро всегда работает в прерываниях Все-таки, прерывание - это всего лишь механизм откладывания дел насущных на чуть-чуть потом. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Forger 26 12 октября, 2023 Опубликовано 12 октября, 2023 · Жалоба 1 hour ago, haker_fox said: что Cortex-Mx всегда работает в прерываних, где главный цикл (пусть даже с ОСРВ) - прерывание, только нулевого уровня прерывание - это когда что-то прервали, если этого "что-то" не существует, то это вовсе не прерывание Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 239 12 октября, 2023 Опубликовано 12 октября, 2023 · Жалоба 5 часов назад, haker_fox сказал: можно взять любую восьмибитку (avr, pic, что угодно) и тоже заставить код выполняться в обработчике хоть несколько часов. При этом код главного цикла не получит управления на любой из озученных архитектур. Или что Вы имели в виду? Вы до сих пор мыслите в парадигме "суперлупа". А надо мыслить - в парадигме событийно-ориентированного программирования. Где нет никаких "главных циклов". Даже в простых проектах. А говорил я о функционале бита SLEEPONEXIT регистра "System Control Register" ядра. Т.е. - вводя SLEEPONEXIT, разработчики уже заведомо предусмотрели модель использования CPU "всегда только в ISR". Без каких-либо "главных циклов". 3 часа назад, Forger сказал: У них обычно очень простой контроллер прерываний - пока одно прерывание не закончиться, остальные будут молча ждать своей очереди, т.е. нет "вытеснения". У простейшего STM8 - и то есть. Хоть и мало уровней приоритета. 3 часа назад, Forger сказал: это только если в проекте вообще не используется RTOS или ее подобие В такой модели сами ISR выполняют роль "задач ОС". А сам CPU можно считать вытесняющей RTOS-ью. 2 часа назад, haker_fox сказал: Речь у уважаемого @jcxz шла о прерывании, т.е. там было единственное число. Кто мешает самому низкоуровневому прерыванию выполняться долго? Одному. А может даже и не самому низкоуровневому - почему нет? 2 часа назад, Arlleex сказал: прерывание - это всего лишь механизм откладывания дел насущных на чуть-чуть потом. "Чуть-чуть" - понятие растяжимое. Сииииииииильно растяжимое. 1 час назад, Forger сказал: прерывание - это когда что-то прервали, если этого "что-то" не существует, то это вовсе не прерывание Конечно прервали. Прервали состояние сна CPU. См.описание бита SCR.SLEEPONEXIT в мануале. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
haker_fox 61 12 октября, 2023 Опубликовано 12 октября, 2023 · Жалоба 1 hour ago, jcxz said: Вы до сих пор мыслите в парадигме "суперлупа". А надо мыслить - в парадигме событийно-ориентированного программирования. Где нет никаких "главных циклов". Даже в простых проектах. Скорее всего таки и есть. Что ж, пищу для размышления Вы мне дали💗 Значит, уже есть возможность изменить свои взгляды. 1 hour ago, jcxz said: А говорил я о функционале бита SLEEPONEXIT регистра "System Control Register" ядра. Т.е. - вводя SLEEPONEXIT, разработчики уже заведомо предусмотрели модель использования CPU "всегда только в ISR". Без каких-либо "главных циклов". Гм. Интересный подход: получается, даже специальная команда, загоняющая ядро в сон не требуется. Закончил обрабатывать все ожидающие прерывания, и уснул. Наступило событие для возникновения прерывания: проснулся, сделал и снова в сон. Надо обдумать. Пока не очень хорошо понимаю всю картину целиком. Спасибо!🙏 3 hours ago, Arlleex said: jcxz имел в виду событийный/энергосберегающий режим работы ядра - когда по выходу из обработчика ядро засыпает, а пробудить его может очередной запрос на прерывание, сгенерированный каким-то событием. Вот с точки зрения МК это и будет жизнью внутри прерывания. @Arlleex, Вы, как всегда на высоте, и в самом приятном смысле в который раз удивляете меня своими знаниями!💗 Спасибо!🙏 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 239 12 октября, 2023 Опубликовано 12 октября, 2023 · Жалоба 7 минут назад, haker_fox сказал: Гм. Интересный подход: получается, даже специальная команда, загоняющая ядро в сон не требуется. Закончил обрабатывать все ожидающие прерывания, и уснул. Наступило событие для возникновения прерывания: проснулся, сделал и снова в сон. Конечно! Именно такая модель использования и задумывалась разработчиками ядра. Уже в само ядро они заложили событийно-ориентированное программирование. Суперлупы - это тяжкое наследие абдурины. От которого давно пора избавиться. Но как переделать мышление большой массы кодеров??? 7 минут назад, haker_fox сказал: @Arlleex, Вы, как всегда на высоте, и в самом приятном смысле в который раз удивляете меня своими знаниями! Да вообще-то SLEEPONEXIT - всегда был. С самого начала эры Cortex-M. 1 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 183 12 октября, 2023 Опубликовано 12 октября, 2023 · Жалоба 15 часов назад, amaora сказал: не могу найти подробную информацию (ни у ST ни у ARM), в частности по регистрам DCCIMVAC и подобным, можно ли туда невыровненный адрес писать или нет? Нельзя. Адрес должен быть выровнен на гранулярность кэш-строки (32 байта?). Вернее, писать Вы туда можете что угодно, но биты [5...0] анализироваться не будут. P.S. Почему бы не воспользоваться CMSIS-макросами, которые уже правильно работают с D-кэшем? Вы, вон, в одном месте флушите/обновляете через SCB_...(), а в другом, почему-то, напрямую к регистрам управления кэшем обращаетесь. Почему? 24 минуты назад, jcxz сказал: Суперлупы - это тяжкое наследие абдурины. От которого давно пора избавиться. Но как переделать мышление большой массы кодеров??? На вскидку можете сказать, например, вот что: есть ли у AVR такой режим? У меня одна железяка есть на AVR, а другое ее исполнение - на ARM Cortex-M3. Устройства работают абсолютно одинаково по не очень длинному суперциклу, где состояния переключаются по некому таймауту и другим событиям. Более того, устройство спать не может, ибо должно постоянно опрашивать дискретный вход на предмет аварии: старый вариант платы (на AVR) не предусматривал заведение этого сигнала на хоть какое-то прерывание. Поэтому для двух исполнений код бизнес-логики - как раз в суперцикле, отличия только в файлах реализации драйверов периферии. Т.е. мысль проста - там, где подразумевается работа на нескольких архитектурах, нет особого смысла каждый раз писать заново: конечно, если речь не о сохранении драгоценных микроампер. 1 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 140 12 октября, 2023 Опубликовано 12 октября, 2023 · Жалоба 1 час назад, jcxz сказал: Т.е. - вводя SLEEPONEXIT, разработчики уже заведомо предусмотрели модель использования CPU "всегда только в ISR". Без каких-либо "главных циклов". А у меня в фоне крутится scmRTOS, у которой переключатель контекста при переключении на IdleTask этот бит взводит, а при переключении на любой другой - сбрасывает. То есть прерывания могут как максимально быстро делать что-то, не требующее участия ОС, так и при необходимости будить задачи ОС. 1 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 239 12 октября, 2023 Опубликовано 12 октября, 2023 · Жалоба 49 минут назад, Arlleex сказал: На вскидку можете сказать, например, вот что: есть ли у AVR такой режим? У меня одна железяка есть на AVR В AVR-ах ничего не смыслю - не имел дел с ними никогда. Но простейший 8-битный STM8 имеет точно такой же режим (там даже команда WFI имеется ) Ну и в конце-концов - а кто выбирал МК? Не Вы ли сами? Кто мешал выбрать другой МК? Тот же STM8 (если речь об экономии)? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться