Перейти к содержанию
    

2 часа назад, kan35 сказал:

И как уже сказали, сидеть в прерывании 30мкс - не правильно.

Не надо повторять чужой вздор.

2 часа назад, kan35 сказал:

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

Детям в начальной школе тоже объясняют, что "делить на ноль нельзя". И только в старших классах (или ВУЗе?) они узнают, что всё-таки можно.  :mosking:

Если вы когда-нибудь откроете и почитаете мануал на ядро Cortex-M, то с удивлением обнаружите, что его разработчики заранее заложили в него возможность работать всегда в прерывании. Т.е. - вообще 100% времени находиться в прерывании. И это - нормальный режим работы ядра. Не то что какие-то мкс, а часы может там сидеть. И это - норма.

2 часа назад, kan35 сказал:

Поэтому перетаскивайте всё в поток и не мудрите.

А ничего, что у автора могут быть другие менее приоритетные ISR? Не задумывались?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Все получается, велосипед едет. Оказалось необходимо использовать DMA2 (и соответственно TIM8) для доступа к AHB на которой GPIO. Перезапуск передачи (вызов AS5047_get_EP) занимает около ~100 тактов на F4.

dma4.png.daf5e74f9472de9af58b07996ba3d9b1.png

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 и подобным, можно ли туда невыровненный адрес писать или нет?

Изменено пользователем amaora

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Что-то не понятно, для чего в

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 - сами массивы расположены в кэшируемом регионе ОЗУ? По кэш-строке выровнили адрес размещения?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

12 minutes ago, Arlleex said:
 


При вызове и выходе из неблокирующей SPI_transfer_dma() хотите забрать в rxbuf принятые данные предыдущей транзакции?

Инвалидация нужна чтобы прочитать rxbuf из памяти а не старые значения из кэша. Да, забираю результат предыдущей транзакции.

В моем случае действительно проще объявить все dma данные выровненными. У меня вся RAM кэшируется, MPU не настраивал.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

On 10/3/2023 at 5:20 PM, jcxz said:

Не то что какие-то мкс, а часы может там сидеть. И это - норма.

Кстати, мне вот подумалось: а чем это ядро так уникально в этом плане? В принципе, можно взять любую восьмибитку (avr, pic, что угодно) и тоже заставить код выполняться в обработчике хоть несколько часов. При этом код главного цикла не получит управления на любой из озученных архитектур. Или что Вы имели в виду?💗

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 hour ago, haker_fox said:

 взять любую восьмибитку (avr, pic, что угодно)

У них обычно очень простой контроллер прерываний - пока одно прерывание не закончиться, остальные будут молча ждать своей очереди, т.е. нет "вытеснения".

On 10/3/2023 at 12:20 PM, jcxz said:

часы может там сидеть. И это - норма

это только если в проекте вообще не используется RTOS или ее подобие

т.е. в таких простых проектах, в таких обычно в конце main() ставят бесконечный цикл и тогда действительно можно хоть вечно "жить" в прерывании

 

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

23 minutes ago, Forger said:

У них обычно очень простой контроллер прерываний - пока одно прерывание не закончиться, остальные будут молча ждать своей очереди, т.е. нет "вытеснения".

Речь у уважаемого @jcxz шла о прерывании, т.е. там было единственное число. Если тут нет опечатки, то вот это и стало интересным. Если речь о множественном числе, т.е. о прерываниях, то тут, конечно же, другие ядра с их контроллерами прерываний несколько проигрывают. Теоретически можно сказать, что Cortex-Mx всегда работает в прерываних, где главный цикл (пусть даже с ОСРВ) - прерывание, только нулевого уровня. "Под ним" ничего нет...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

9 часов назад, amaora сказал:

В моем случае действительно проще объявить все dma данные выровненными.

Вообще, по-хорошему, так нужно делать всегда, т.к. постоянно в каждом месте применения флуша/инвалидации думать, а какие же еще там рядом переменные в той же строке кэша лежат - занятие неблагодарное, так не делают:smile:
 

38 минут назад, haker_fox сказал:

Речь у уважаемого @jcxz шла о прерывании, т.е. там было единственное число. Если тут нет опечатки, то вот это и стало интересным.

jcxz имел в виду событийный/энергосберегающий режим работы ядра - когда по выходу из обработчика ядро засыпает, а пробудить его может очередной запрос на прерывание, сгенерированный каким-то событием.

Вот с точки зрения МК это и будет жизнью внутри прерывания.
 

Цитата

Теоретически можно сказать, что Cortex-Mx всегда работает в прерываних, где главный цикл (пусть даже с ОСРВ) - прерывание, только нулевого уровня. "Под ним" ничего нет...

У Cortex-M есть такое понятие как приоритет выполнения (execution priority), он зависит от режима CPU (thread/handler). Технически это позволило реализовать поток инструкций для обработчика прерывания неотличимым от инструкций основного потока (в отличие от того же AVR с их ret/reti). Но вряд ли тут можно провести прямую параллельную мысль, что ядро всегда работает в прерываниях:smile: Все-таки, прерывание - это всего лишь механизм откладывания дел насущных на чуть-чуть потом.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 hour ago, haker_fox said:

что Cortex-Mx всегда работает в прерываних, где главный цикл (пусть даже с ОСРВ) - прерывание, только нулевого уровня

прерывание - это когда что-то прервали,

если этого "что-то" не существует, то это вовсе не прерывание

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

5 часов назад, haker_fox сказал:

можно взять любую восьмибитку (avr, pic, что угодно) и тоже заставить код выполняться в обработчике хоть несколько часов. При этом код главного цикла не получит управления на любой из озученных архитектур. Или что Вы имели в виду?

Вы до сих пор мыслите в парадигме "суперлупа". А надо мыслить - в парадигме событийно-ориентированного программирования. Где нет никаких "главных циклов". Даже в простых проектах.

А говорил я о функционале бита SLEEPONEXIT регистра "System Control Register" ядра. Т.е. - вводя SLEEPONEXIT, разработчики уже заведомо предусмотрели модель использования CPU "всегда только в ISR". Без каких-либо "главных циклов".

3 часа назад, Forger сказал:

У них обычно очень простой контроллер прерываний - пока одно прерывание не закончиться, остальные будут молча ждать своей очереди, т.е. нет "вытеснения".

У простейшего STM8 - и то есть. Хоть и мало уровней приоритета.

3 часа назад, Forger сказал:

это только если в проекте вообще не используется RTOS или ее подобие

В такой модели сами ISR выполняют роль "задач ОС". А сам CPU можно считать вытесняющей RTOS-ью.  :biggrin:

2 часа назад, haker_fox сказал:

Речь у уважаемого @jcxz шла о прерывании, т.е. там было единственное число.

Кто мешает самому низкоуровневому прерыванию выполняться долго? Одному. А может даже и не самому низкоуровневому - почему нет?

2 часа назад, Arlleex сказал:

прерывание - это всего лишь механизм откладывания дел насущных на чуть-чуть потом.

"Чуть-чуть" - понятие растяжимое. Сииииииииильно растяжимое.  :unknw:

1 час назад, Forger сказал:

прерывание - это когда что-то прервали,

если этого "что-то" не существует, то это вовсе не прерывание

Конечно прервали. Прервали состояние сна CPU. :wink:  См.описание бита SCR.SLEEPONEXIT в мануале.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 hour ago, jcxz said:

Вы до сих пор мыслите в парадигме "суперлупа". А надо мыслить - в парадигме событийно-ориентированного программирования. Где нет никаких "главных циклов". Даже в простых проектах.

Скорее всего таки и есть. Что ж, пищу для размышления Вы мне дали💗 Значит, уже есть возможность изменить свои взгляды.

1 hour ago, jcxz said:

А говорил я о функционале бита SLEEPONEXIT регистра "System Control Register" ядра. Т.е. - вводя SLEEPONEXIT, разработчики уже заведомо предусмотрели модель использования CPU "всегда только в ISR". Без каких-либо "главных циклов".

Гм. Интересный подход: получается, даже специальная команда, загоняющая ядро в сон не требуется. Закончил обрабатывать все ожидающие прерывания, и уснул. Наступило событие для возникновения прерывания: проснулся, сделал и снова в сон. Надо обдумать. Пока не очень хорошо понимаю всю картину целиком.

Спасибо!🙏

3 hours ago, Arlleex said:

jcxz имел в виду событийный/энергосберегающий режим работы ядра - когда по выходу из обработчика ядро засыпает, а пробудить его может очередной запрос на прерывание, сгенерированный каким-то событием.

Вот с точки зрения МК это и будет жизнью внутри прерывания.

@Arlleex, Вы, как всегда на высоте, и в самом приятном смысле в который раз удивляете меня своими знаниями!💗 Спасибо!🙏

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

7 минут назад, haker_fox сказал:

Гм. Интересный подход: получается, даже специальная команда, загоняющая ядро в сон не требуется. Закончил обрабатывать все ожидающие прерывания, и уснул. Наступило событие для возникновения прерывания: проснулся, сделал и снова в сон.

Конечно! Именно такая модель использования и задумывалась разработчиками ядра. Уже в само ядро они заложили событийно-ориентированное программирование.

Суперлупы - это тяжкое наследие абдурины. От которого давно пора избавиться. Но как переделать мышление большой массы кодеров???

7 минут назад, haker_fox сказал:

@Arlleex, Вы, как всегда на высоте, и в самом приятном смысле в который раз удивляете меня своими знаниями!

Да вообще-то SLEEPONEXIT - всегда был. С самого начала эры Cortex-M.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

15 часов назад, amaora сказал:

не могу найти подробную информацию (ни у ST ни у ARM), в частности по регистрам DCCIMVAC и подобным, можно ли туда невыровненный адрес писать или нет?

Нельзя. Адрес должен быть выровнен на гранулярность кэш-строки (32 байта?). Вернее, писать Вы туда можете что угодно, но биты [5...0] анализироваться не будут.

P.S. Почему бы не воспользоваться CMSIS-макросами, которые уже правильно работают с D-кэшем?

Вы, вон, в одном месте флушите/обновляете через SCB_...(), а в другом, почему-то, напрямую к регистрам управления кэшем обращаетесь. Почему?
 

24 минуты назад, jcxz сказал:

Суперлупы - это тяжкое наследие абдурины. От которого давно пора избавиться. Но как переделать мышление большой массы кодеров???

На вскидку можете сказать, например, вот что: есть ли у AVR такой режим? У меня одна железяка есть на AVR, а другое ее исполнение - на ARM Cortex-M3. Устройства работают абсолютно одинаково по не очень длинному суперциклу, где состояния переключаются по некому таймауту и другим событиям. Более того, устройство спать не может, ибо должно постоянно опрашивать дискретный вход на предмет аварии: старый вариант платы (на AVR) не предусматривал заведение этого сигнала на хоть какое-то прерывание. Поэтому для двух исполнений код бизнес-логики - как раз в суперцикле, отличия только в файлах реализации драйверов периферии.

Т.е. мысль проста - там, где подразумевается работа на нескольких архитектурах, нет особого смысла каждый раз писать заново: конечно, если речь не о сохранении драгоценных микроампер.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 час назад, jcxz сказал:

Т.е. - вводя SLEEPONEXIT, разработчики уже заведомо предусмотрели модель использования CPU "всегда только в ISR". Без каких-либо "главных циклов".

А у меня в фоне крутится scmRTOS, у которой переключатель контекста при переключении на IdleTask этот бит взводит, а при переключении на любой другой - сбрасывает. То есть прерывания могут как максимально быстро делать что-то, не требующее участия ОС, так и при необходимости будить задачи ОС.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

49 минут назад, Arlleex сказал:

На вскидку можете сказать, например, вот что: есть ли у AVR такой режим? У меня одна железяка есть на AVR

В AVR-ах ничего не смыслю - не имел дел с ними никогда. Но простейший 8-битный STM8 имеет точно такой же режим (там даже команда WFI имеется :wink: )

Ну и в конце-концов - а кто выбирал МК? Не Вы ли сами? :wink: Кто мешал выбрать другой МК? Тот же STM8 (если речь об экономии)?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...