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();
}
}
#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, не помогло.
Вопрос: как заставить компилятор оптимизировать или не оптимизировать нужные мне куски кода??
Спасибо
