Zol'berg 0 13 мая, 2013 Опубликовано 13 мая, 2013 · Жалоба Всем привет!! 1. Из инструментов при себе имею STM32F407 - Discovery, CooCox и осцилл (2ch x 100MHz). 2. Задача: захватить 16 разрядные данные с ADC (4 канала) по протоколу SPI при тактовой частоте 5MHz (CLK). 3. Решение: программная реализация протокола ввиду наличия лишь 3_ёх SPI в STM32F407 и некоторых отклонений входного потока от стандарта SPI (исходные условия), при тактовой в 168 MHz хватает впритык и только с оптимизатором -O3. Программка выглядит так: // Соответствие функций входных линий и ножек порта: #define SCK 1<<4 #define NSS 1<<5 #define MOSI_SPI0 1<<0 #define MOSI_SPI1 1<<1 #define MOSI_SPI2 1<<2 #define MOSI_SPI3 1<<3 #define N_DATA 10 // количество данных (выборок) uint16_t DATA_0[N_DATA]; // Массив отсчетов для 0_го канала uint16_t DATA_1[N_DATA]; // Массив отсчетов для 1_го канала uint16_t DATA_2[N_DATA]; // Массив отсчетов для 2_го канала uint16_t DATA_3[N_DATA]; // Массив отсчетов для 3_го канала uint16_t DATA_temp[16]; // Буфера для сохранения состояний порта, (для повышения быстродействия) uint16_t N_Data; // Счетчик/номер текущего отсчета в периоде захвата или выдачи данных uint8_t i; // Само собой разумеется void SSS(void) // Ф-ия преобразования сохраненных состояний порта DATA_temp[i] в отчеты DATA_0-3[N_Data] { i=0; DATA_0[N_Data] = 0; while(i<16) for(i=0;i<16;i++) { if((DATA_temp[i] & MOSI_SPI0 == MOSI_SPI0) ) DATA_0[N_Data] |= (0x8000>>i); i++; } i=0; DATA_1[N_Data] = 0; while(i<16) { if((DATA_temp[i] & MOSI_SPI1) == MOSI_SPI1) DATA_1[N_Data] |= (0x8000>>i); i++; } i=0; DATA_2[N_Data] = 0; while(i<16) { if((DATA_temp[i] & MOSI_SPI2) == MOSI_SPI2) DATA_2[N_Data] |= (0x8000>>i); i++; } i=0; DATA_3[N_Data] = 0; while(i<16) { if((DATA_temp[i] & MOSI_SPI3) == MOSI_SPI3) DATA_3[N_Data] |= (0x8000>>i); i++; } } void Flag(void) // Ф-ия "Флаг" - "контрольная точка" { GPIOD->BSRRL =(1<<14); // set GPIOD->BSRRH =(1<<14); // clr } void ProgramSPI(void) // Программная реализация SPI где D0-MOSI(SPI0)|D1-MOSI(SPI1)|D2-MOSI(SPI2)|D3-MOSI(SPI3) D4-SCK D5-NSS { N_Data=0; { while ((GPIOD->IDR & NSS) == 0)// NSS==0 (ждем начала выполнения преобразования ADC) {} while ((GPIOD->IDR & NSS) == NSS)// NSS==1 (ждем окончания выполнения преобразования ADC) {} // Flag(); // Процесс захвата данных (SPI0-3): i=0; while (i<16) { while ((GPIOD->IDR & (NSS|SCK)) != SCK) // SCK!=1|NSS==0 {} Flag(); DATA_temp[i]=GPIOD->IDR; Flag(); while ((GPIOD->IDR & (NSS|SCK)) != 0) // SCK!=0|NSS==0 {} // Flag(); i++; } SSS(); // Проверка принятых байтов: if((DATA_0[N_Data]!= 0xA38C) | (DATA_1[N_Data]!= 0xA38C) | (DATA_2[N_Data]!= 0xA38C) | (DATA_3[N_Data] != 0xA38C)) { Flag(); } N_Data++; // Инкремент счетчика отсчетов - подготовка к следующему полуслову if(N_Data==N_DATA) return; // Переполнение буфера данных, возврат в main() } } int main(void) // Очень странная функция !!!;) { SystemInit(); PortD_Init(); while(1) { ProgramSPI(); } } В общем все работает, ф-ия Flag() - контрольная точка (выводит строб на порт который контролируется осциллографом), ProgramSPI() сохраняет состояние ножек порта в нужное время 16 раз, ф-ия SSS() преобразует данные, но есть одно НО, при подключении вызова ф-ии SSS() компилятор отказывается оптимизировать код в сторону быстродействия, т.е. другими словами - в случае применения где либо этих массивов, скорости не хватает и появляются ошибки чтения. Пытался применять квалификаторы типа volatile и restrict, не помогло. Вопрос: как заставить компилятор оптимизировать или не оптимизировать нужные мне куски кода?? Спасибо :) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
demiurg_spb 0 13 мая, 2013 Опубликовано 13 мая, 2013 · Жалоба Посмотрите на мой примерчик: //============================================================================= // With SPI Modes 0 and 3, data is always latched in on the rising edge of SCK and always output on the falling edge of SCK //============================================================================= uint_fast8_t spi_transfer(uint_fast8_t data) { for (int_fast8_t i=0; i<8; i++) { SPI_SCK(0); SPI_MOSI(data & (1<<7)); // write data at the begin of cycle spi_delay(); SPI_SCK(1); spi_delay(); data = (data<<1) | SPI_MISO(); // read data at the end of cycle } return (data & 0xff); // clr possible garbage } для отправки 16-ти битных данных легко модифицируется + следующие макросы через bitband реализуйте, если у F4 порты в его доступе... SPI_SCK(X) SPI_MOSI(X) SPI_MISO() Не будет хватать скорости - разверните циклы... А вообще ваш код меня сильно-сильно коробит... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Zol'berg 0 13 мая, 2013 Опубликовано 13 мая, 2013 (изменено) · Жалоба Может я чего не пойму, но у меня только приемник (slave), т.е. я не управляю, а слежу за состоянием SCK и NSS, и параллельно снимаю 4 потока данных, И не пойму, как реализовать проверку состояния порта через bitband (Ваш SPI_MISO())??? P.S. Все те угрюмые навороты в моей проге только по причине нехватки скорости (проверка состояния входа через маску - ~40 ns) , как через bitband проверить, ведь регистр BSRR только для установки и сброса !?? Изменено 13 мая, 2013 пользователем Zol'berg Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
demiurg_spb 0 13 мая, 2013 Опубликовано 13 мая, 2013 · Жалоба И не пойму, как реализовать проверку состояния порта через bitband (Ваш SPI_MISO())??? А регистр IDR на что? Он у F4xx лежит в bitband области? У F1xx лежит, что очень удобно. ...у меня только приемник (slave), т.е. я не управляю, а слежу за состоянием SCK и NSS...С этого и стоило начинать... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
RabidRabbit 0 13 мая, 2013 Опубликовано 13 мая, 2013 · Жалоба В функции SSS() вполне достаточно одного цикла на все 4 канала :) И как уже советовали, этот цикл можно и развернуть (хотя это и компилятор может сделать). Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Zol'berg 0 13 мая, 2013 Опубликовано 13 мая, 2013 · Жалоба Ну, к регистру IDR необходимо применять маску, я так и делаю, а это время, а 5 MHz SCK это много! Когда я работал на Асме на AVR было четко и ясно, за 2 такта я мог опросить любой бит одной командой, а тут за 8 еле еле, и C компилятор живет своей жизнью, хочет разгоняет, а хочет тормозит! И что делать? В функции SSS() вполне достаточно одного цикла на все 4 канала Да, ты прав, наворотил я здесь . Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
demiurg_spb 0 13 мая, 2013 Опубликовано 13 мая, 2013 · Жалоба Ну, к регистру IDR необходимо применять маску, я так и делаю Вы не понимаете что такое bitband + Карта памяти Там маски не нужны будут. Сразу считываешь 0 или 1 и пакуешь в байты data = (data<<1) | SPI_MISO(); Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Zol'berg 0 13 мая, 2013 Опубликовано 13 мая, 2013 (изменено) · Жалоба Да, я все равно никак не пойму что такое и как работает bitband применительно к СЧИТЫВАНИЮ порта, с регистром BSRR(BSRRL и BSRRH) я знаком! Если я не ошибаюсь bitband это метод установки/сброса и никак не касается считывания!? Ну, а SPI_MISO() из чего сделано? Изменено 13 мая, 2013 пользователем Zol'berg Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
demiurg_spb 0 13 мая, 2013 Опубликовано 13 мая, 2013 · Жалоба Вы читать умеете? Я же дал вам ссылки - там всё написано. Bitband вообще никак не связан ни счем. Это просто способ атомарно прочитать или записать один бит. И не важно где этот бит лежит. Хоть в регистре BSSR хоть IDR, хоть где... Ну, а SPI_MISO() из чего сделано? У кого как... У меня для cm3 из этого: static __inline volatile uint32_t* bb_bit_address(volatile uint32_t* p, uint_fast8_t bit) { return ( (volatile uint32_t*) (((uint32_t)p & 0xf0000000UL) | 0x02000000UL +(((uint32_t)p & 0x000fffffUL)<<5) | (bit<<2))); } Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
aoreh 0 22 мая, 2013 Опубликовано 22 мая, 2013 · Жалоба 3. Решение: программная реализация протокола ввиду наличия лишь 3_ёх SPI в STM32F407 и некоторых отклонений входного потока от стандарта SPI (исходные условия), при тактовой в 168 MHz хватает впритык и только с оптимизатором -O3. может имеет смысл попробовать приспособить USART в синхронном режиме? или совсем никак? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться