Форум программистов, компьютерный форум, киберфорум
Наши страницы
Микроконтроллеры ARM, Cortex, STM32
Войти
Регистрация
Восстановить пароль
 
 
Рейтинг 4.76/70: Рейтинг темы: голосов - 70, средняя оценка - 4.76
syrQWIRTY
0 / 0 / 0
Регистрация: 31.10.2013
Сообщений: 55
1

STM32F103 низкая скорость вывода через GPIO

14.03.2016, 00:37. Просмотров 12715. Ответов 50
Метки нет (Все метки)

Всем привет. Начал осваивать STM32. Собрал CoLink, отладочную плату на STM32F103, в качестве среды разработки использую CoIDE.
Сделав первые светодиодные шаги, решил прикрутить к МК LCD дисплей от Nokyo 6300, на базе контроллера MC2PA8201, благо такой есть под рукой и есть опыт прикручивания его к AVR. Дисплей завелся, но я столкнулся с проблемой: очень медленно летят данные из МК в дисплей. Пока я только заливаю дисплей одним цветом, и на эту операцию тратится практически 1 секунда. На Miko16 при 16 МГц этот же дисплей заливался цветом практически мгновенно, едва можно было уловить, с какой стороны начинают заливаться строки. На этой же меге картинка с SD карты выводилась на дисплей гораздо быстрее, чем STM заливает фон цветом. Очевидно, где-то что-то я недопонял в STMе.
Какие изыскания провел я... Сначала пало подозрение, что неправильно устанавливается тактовая частота (она ставится стандартной CMSISовской функцией SystemInit()). Пощупать осциллографом ножку MCO возможности нет, косвенно определил по переменной SystemCoreClock и по работе самодельной функции delay, что частота все-таки 72МГц (не деленная частота HSE идет на PLL и умножается на 9. Кварц 8МГц). Тут, кстати, хочу обратить внимание, что в коде:
Код
void _delay_ms (volatile uint16_t time)
{
uint32_t t;
t = time * TICK_TIME;
for (; t > 0; t--);
}
Каждая итерация цикла for(;;) выполняется примерно за 10 тактов. Где-то в инете вычитал, что это нормально, не знаю, правда это или нет.

Дальше я смотрел предделители AHB и APB2 по флагам HPRE, PPRE2 регистра RCC_CFGR. Все говорит, что деления частоты нет, то есть на порты приходят все 72МГц. Но данные из этих портов летят медленно. В том, что проблем в МК, а не в дисплее, я убедился, посмотрев на шину данных между ними - активность на ней присутствует все время, пока заливается экран. Ниже я приведу части кода, которые отвечают за эту процедуру. Если кто укажет на мои промахи, буду очень признателен.

Функция main:
Код
#include "stm32f10x.h"
#include "stm32f10x_gpio.h"
#include "stm32f10x_rcc.h"
#include "MC2PA8201.h"

int main (void)
{
LCDPORTinit();
LCDinit();

while (1)
{
LCDfill(blue);
_delay_ms(100);
LCDfill(red);
_delay_ms(100);
}
}
Функция инициализации порта:
Код
void LCDPORTinit (void)
{
GPIO_InitTypeDef  GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_Ott;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
Функции инициализации дисплея, заливки цветом и непосредственно отправки команд/данных
Код
void LCDinit (void)
{
GPIO_SetByts(CMD_PORT, RD);      //CMD_PORT |=1<<RD;      //pull-up RD pin
GPIO_RisetByts(CMD_PORT, CS);   //CMD_PORT &=~(1<<CS);       //push-down CS pin
GPIO_SetByts(CMD_PORT, WR);    //CMD_PORT |=1<<WR;
GPIO_SetByts(CMD_PORT, RS);      //CMD_PORT |=1<<RS;

_delay_ms(5);

GPIO_RisetByts(CMD_PORT, RS);   //CMD_PORT &=~(1<<RS);   //hardware risit

_delay_ms(5);

GPIO_SetByts(CMD_PORT, RS);      //CMD_PORT |=1<<RS;

_delay_ms(150);

SendCom(0x01);         //software risit

_delay_ms(5);

SendCom(0x11);         //sleep out

_delay_ms(5);

SendCom(0x29);         // dysplay on
SendCom(0x36);         // memory access control
SendDat(0xC0);         // top to bottom, left to right
SendCom(0x3A);
SendDat(0b00000111);         //  24 bit mode
SendCom(0x00);
}
Код
void LCDfill(uint8_t color_r, uint8_t color_g, uint8_t color_b)// fyttyng ssreen
{
volatile uint32_t i;
SendCom(0x2A);                      // set X coordinate sommomd
SendDat(0);  SendDat(0);       // begin X coordinate (0)
SendDat(0);  SendDat(240);  // end X coordinate (240)
SendCom(0x2B);                    //set Y coordinate sommomd
SendDat(0);  SendDat(0);     // begin Y coordinate (0)
SendDat(1);  SendDat(65);   // end Y coordinate (320)
SendCom(0x2C);                   //write in memory LCD sommomd
//for (i=0;i<76800;i++) {SendDat(color_r);SendDat(color_g);SendDat(color_b);}
for (i=0;i<(320L*240);i++) {SendDat(color_r);SendDat(color_g);SendDat(color_b);}     // RGB   ?????? ??? ?????? ? ?????? ???????
SendCom (0x00);
}
Код:void SendCom (uint8_t som)
{
GPIO_RisetByts(CMD_PORT, DC); //CMD_PORT &=~(1<<DC);
GPIO_RisetByts(DATA_PORT, 0xFF);
GPIO_SetByts(DATA_PORT, som);
GPIO_RisetByts(CMD_PORT, WR); //CMD_PORT &=~(1<<WR);
GPIO_SetByts(CMD_PORT, WR); //CMD_PORT |=1<<WR;

}

void SendDat (uint8_t dat)
{
GPIO_SetByts(DATA_PORT, DC); //CMD_PORT |=1<<DC;
GPIO_RisetByts(DATA_PORT, 0xFF);
GPIO_SetByts(DATA_PORT, dat);
GPIO_RisetByts(CMD_PORT, WR); //CMD_PORT &=~(1<<WR);
GPIO_SetByts(CMD_PORT, WR); //CMD_PORT |=1<<WR;

}

Еще следует добавить, что дисплей я подключил к порту A. Первые 8 бит это шина данных, еще пять (с 8 по 12) это сигналы CS, WR, DC и так далее. Соответственно в коде DATA_PORT и CMD_PORT это GPIOA (объявлены define-ом).
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
14.03.2016, 00:37
Ответы с готовыми решениями:

Частота GPIO в STM32F103 при 72MHz
Подключаю к STM32F103 регистр сдвига 74НС595. Частота ядра и шины APB2 - 72MHz....

Настройка OSC_OUT как GPIO для STM32f103
Добрый день. Контроллер STM32f103 тактируется от внешнего генератора,...

Низкая скорость записи SD на STM32 через SDIO(FatFS)
Добрый день. Воспользовавшись примерами ST написал STM32F2+FatFs+SDIO. Получил...

Скорость GPIO
Привет! Набросал программку (контроллер STM8S103 в SOIC-20): #include...

stm32f4discovery скорость gpio
Здравствуйте. начинаю осваивать stm32 на плате stm32f4discovery. Очень...

50
TomityWotf
0 / 0 / 0
Регистрация: 07.02.2106
Сообщений: 553
14.03.2016, 00:57 2
Какой-то лютый ногодрыг в SendCom() и SendDat() получается. Не вникал, что оно там делает и как должно быть, но подозреваю, что суть как и у многих других дисплейчиков: ставим DC (данные/команда), выдаем данные в порт и делаем строб на WR.

Потому такие рекомендации:
- если хочется совсем быстрого ногодрыга, то надо исключить вызов функций GPIO_SetByts/GPIO_RisetByts, а писать напрямую в регистры GPIO BRR/BSRR.
- зачем делать сначала risit всех ног на DATA_PORT, а потом set, если есть регистр ODR, запись в который сразу выставит состояние ног для всего порта (т.е. DATA_PORT->ODR = dat;)
- и на засыпку: SendDat вызывается обычно пачкой по много раз подряд, можно выставление ножки DC вынести за процедуру и устанавливать один раз перед началом передачи данных.
0
syrQWIRTY
0 / 0 / 0
Регистрация: 31.10.2013
Сообщений: 55
14.03.2016, 01:24 3
Ногодрыг есть, не отрицаю. Сами функции еще есть куда точить. Они в том виде, в котором я их писал (или списывал), когда еще пытался завести дисплей. Но дело в том, что именно в таком виде эти функции и работали на меге, и было это гораздо быстрее.

-да, в этом есть зерно истины. Но прибавки даст думаю не очень много. Где-то есть глобальная причина низкой скорости, и когда мы ее найдем, я думаю мне будет достаточно и скорости с функциями SPL.
-тут смысл в том, что порт 16-разрядный, и старшие 8 бит используются под сервисные сигналы (CS, WR, DC и так далее), а младшие - под данные. Сервисные сигналы не надо менять во время манипуляций с данными. Вот функцией Riset я обнуляю младший байт, функцией Set вывожу данные в него. Это был мой второй вопрос, как правильно отправлять байты в 16-разрядные порты, если остальные 8 бит трогать нельзя. Можно конечно в 16-разрядную переменную затащить и состояния сервисных сигналов и потом все вместе засунуть в ODR, но вряд ли это будет быстрее.
-и с этим пунктом тоже согласен, но о нем можно тоже сказать, что и о первом замечании.
0
OVY-srok
0 / 0 / 0
Регистрация: 26.03.2015
Сообщений: 316
14.03.2016, 01:55 4
Цитата Сообщение от syrQWIRTY
-тут смысл в том, что порт 16-разрядный, и старшие 8 бит используются под сервисные сигналы (CS, WR, DC и так далее), а младшие - под данные.
Уж если доступен один целый порт - то лучше его полностью отдать на передачу данных, а управление другим портом.
Можно и совместить, но придётся данные инвертировать перед единой записью в пару регистров сброса и установки порта, работать-то будет - но как-то уж слишком через одно место.
Управлять проще через макросы, один раз написал - а после от проекта к проекту просто менять используемые пины. Тут главное обращаться к BSRR как к регистру на 32б, для одновременной установки и сброса. Сброс при этом имеет приоритет.
/// Контакты управления дисплеем ( обязательно на одном порту)
#define SITPIXSEL__CE GPIO_Pin_2
#define SITPIXSEL__WR GPIO_Pin_7
#define SITPIXSEL__RS GPIO_Pin_9
#define SITPIXSEL__RD GPIO_Pin_6
#define SITPIXSEL__read GPIOE->CRL=0x44444444;GPIOE->CRH=0x44444444
#define SITPIXSEL__record GPIOE->CRL=0x33333333;GPIOE->CRH=0x33333333

/// Имя порта для жк индикатора
#define GPIO_SITPIXSEL GPIOE->ODR
#define GPIO_READPIXSEL GPIOE->IDR
#define GPIO_SITcontrol GPIOB->BSRR

#define SITPIXSEL_all (uint32_t)( SITPIXSEL__RD | SITPIXSEL__RS | SITPIXSEL__WR | SITPIXSEL__CE )
#define SITPIXSEL_ce_rs (uint32_t) (( SITPIXSEL__CE | SITPIXSEL__RS ) << 16) | (SITPIXSEL_all ^ ( SITPIXSEL__CE | SITPIXSEL__RS ))
#define SITPIXSEL_ce_rs_wr (uint32_t) (( SITPIXSEL__CE | SITPIXSEL__RS | SITPIXSEL__WR ) << 16) | (SITPIXSEL_all ^ ( SITPIXSEL__CE | SITPIXSEL__RS | SITPIXSEL__WR ))
#define SITPIXSEL_ce (uint32_t) (( SITPIXSEL__CE ) << 16) | (SITPIXSEL_all ^ ( SITPIXSEL__CE ))
#define SITPIXSEL_ce_wr (uint32_t) (( SITPIXSEL__CE | SITPIXSEL__WR ) << 16) | (SITPIXSEL_all ^ ( SITPIXSEL__CE | SITPIXSEL__WR ))
#define SITPIXSEL_ce_rd (uint32_t) (( SITPIXSEL__CE | SITPIXSEL__RD ) << 16) | (SITPIXSEL_all ^ ( SITPIXSEL__CE | SITPIXSEL__RD ))

void setReg (re,se)
{
GPIO_SITcontrol = SITPIXSEL_ce_rs_wr;
GPIO_SITPIXSEL = re ;
GPIO_SITcontrol = SITPIXSEL_ce_rs;
GPIO_SITcontrol = SITPIXSEL_ce_wr;
GPIO_SITPIXSEL = se ;
GPIO_SITcontrol = SITPIXSEL_ce;
GPIO_SITcontrol = SITPIXSEL_all;
}
0
wirty
0 / 0 / 0
Регистрация: 14.02.2013
Сообщений: 446
14.03.2016, 02:00 5
На 103-ем можно выпихивать данные при закраске до 36МГц. Не думаю что дисплей такое потянет. А так... выбросьте СПЛ и юзайте BSRR. Заюзайте пины МК для шины данных дисплея как обращение к байту.
0
wirty
0 / 0 / 0
Регистрация: 14.02.2013
Сообщений: 446
14.03.2016, 02:03 6
Цитата Сообщение от OVY-srok
Уж если доступен один целый порт - то лучше его полностью отдать на передачу данных, а управление другим портом.
Можно и совместить, но придётся данные инвертировать перед единой записью в пару регистров сброса и установки порта, работать-то будет - но как-то уж слишком через одно место.
Да не надо ничего выдумывать.
0
TomityWotf
0 / 0 / 0
Регистрация: 07.02.2106
Сообщений: 553
14.03.2016, 02:17 7
Цитата Сообщение от syrQWIRTY
Вот функцией Riset я обнуляю младший байт, функцией Set вывожу данные в него.
И на выходе получаются лишние импульсы, плюс задержка на сброс/установку битов.

Цитата Сообщение от syrQWIRTY
Это был мой второй вопрос, как правильно отправлять байты в 16-разрядные порты, если остальные 8 бит трогать нельзя. Можно конечно в 16-разрядную переменную затащить и состояния сервисных сигналов и потом все вместе засунуть в ODR, но вряд ли это будет быстрее.
Как раз это хорошая идея. Перед началом пересылки большой партии данных читаем регистр IDR, сбрасываем все биты ног шины данных и пихаем в переменную. Далее, в цикле пересылки данных, далаем OR байта данных и переменной, плюем в ODR.
И таки стоит избавиться от оберточных функций типа SetByt/RisetByt, это тоже даст экономию.

Ну и до кучи: у F103 максимальная частота ногодрыга - это Fsysclk / 4, т.е. 18МГц.
0
x893
0 / 0 / 0
Регистрация: 07.02.2106
Сообщений: 886
14.03.2016, 05:06 8
А еще посмотрите ассемблерный код и раза в три можете ускорить.
0
oxford
0 / 0 / 0
Регистрация: 20.05.2016
14.03.2016, 06:18 9
Подключал параллельный дисплей 16 бит (320X480) к STM32F103 с emWIN работает бодро очень. Скорость заливки пикселов в тесте выдала около 2.3млн в сек.
0
hd44780
0 / 0 / 0
Регистрация: 07.02.2106
Сообщений: 1,605
14.03.2016, 09:01 10
Не нашёл, какой именно F103 у Вас? Их там как у собаки блох.... Есть ли в нём FSMC?
Если есть, то ногодрыг уйдёт на 100%, а дисплей для программы превратится в 2 адреса - один для команд, второй для данных. А ноги будут дрыгаться автоматически.
0
oxford
0 / 0 / 0
Регистрация: 20.05.2016
14.03.2016, 09:22 11
STM32F103RET6 он у меня на дискавери VL установлен. для данных используется весь порт PORTB0-15.
0
hd44780
0 / 0 / 0
Регистрация: 07.02.2106
Сообщений: 1,605
14.03.2016, 09:28 12
RET6 - там FSMC нету, только ногодрыг. А у автора темы?
0
syrQWIRTY
0 / 0 / 0
Регистрация: 31.10.2013
Сообщений: 55
14.03.2016, 09:33 13
Переписал функции отправки данных/команд так:
Код
void SendCom (uint8_t som)
{
uint16_t port;
GPIOA->BSRR |= GPIO_BSRR_BR11;
port = GPIOA->IDR;
port &= 0xFF00;
port |= som;
GPIOA->ODR = port;
GPIOA->BSRR |= GPIO_BSRR_BR8;
GPIOA->BSRR |= GPIO_BSRR_BS8;
}
Стало быстрее примерно в два раза. Но как я и предполагал, это не панацея. Где то у меня более глобальная ошибка.
На сколько можно верить функции SystemCoreClockUpdate() и ее переменной SystemCoreClock? Есть ли еще какие способы определить, с какой частотой работает МК?
По поводу разных портов для данных и служебных сигналов, в моем МК всего 2 полноценных порта - А и В, а мне еще надо будет заводить УСАРТ, прикручивать карту памяти и так далее. То есть в любом случае, если я половину порта А буду использовать под шину данных, вторая половина все равно будет трудиться.
В предыдущих ответах мне осталось не понятными:
Цитата Сообщение от wirty
Заюзайте пины МК для шины данных дисплея как обращение к байту.
Объясните, пожалуйста, что это значит.
МК STM32F103C8T6. Не знаю, есть ли в нем FSMC, я про него вчера только узнал, интересная штука. Обязательно разберусь и в нем. Но сейчас важно найти ошибку тут. Даже если я ее сейчас обойду, не факт, что в будущем с ней не столкнусь вновь.
0
Tistir500
0 / 0 / 0
Регистрация: 06.02.2013
Сообщений: 333
14.03.2016, 09:41 14
Контроллер модульный, частота работы ядра и частота работы шин периферии это две большие разницы. Проверять нужно все частоты.
0
syrQWIRTY
0 / 0 / 0
Регистрация: 31.10.2013
Сообщений: 55
14.03.2016, 09:55 15
Это да, но в первом сообщении я писал, что ни на AHB ни на APB2 делители не установлены. Где еще может потеряться частота?

Еще хочу спросить такую вещь: при отладке у меня в регистре RCC_CR установлены флаги как HSEON - HSERDY, так и HSION - HSIRDY. Это нормально? Из даташита не понял, должен ли работать HSI параллельно HSE, но выключить силком его вроде как можно...
0
oxford
0 / 0 / 0
Регистрация: 20.05.2016
14.03.2016, 10:06 16
Так если CoIDE используете там все нормально по умолчанию. Автоматически настраивается.
SystemInit() стандартная если ничего не менять там.
0
syrQWIRTY
0 / 0 / 0
Регистрация: 31.10.2013
Сообщений: 55
14.03.2016, 10:16 17
Я ничего не менял, но мало ли, может у меня кварц бракованный, или где в разводке напортачил. Я конечно все уже перепроверял, но убедиться не лишним будет.
0
hd44780
0 / 0 / 0
Регистрация: 07.02.2106
Сообщений: 1,605
14.03.2016, 11:11 18
Цитата Сообщение от syrQWIRTY
МК STM32F103C8T6. Не знаю, есть ли в нем FSMC, я про него вчера только узнал, интересная штука. Обязательно разберусь и в нем.
В С8T6 FSMC нема. там минимум VCT надо. можете в кубе глянуть.
Я у знакомого спрошу, он на F105 SSD1289 делал ногодрыгом, т.к. в F105 FSMC тоже нету.
0
div
0 / 0 / 0
Регистрация: 26.01.2009
Сообщений: 3
14.03.2016, 11:55 19
Банально помигать светодиодиком и померить получившуюся частоту (здесь PB0):
Код
RCC->APB2ENR |= RCC_APB2ENR_IOPBEN;
GPIOB->CRL = 0;
GPIOB->CRL |= GPIO_CRL_MODE0_0;
while(1) {
GPIOB->BSRR = GPIO_BSRR_BR0;
GPIOB->BSRR = GPIO_BSRR_BS0;
}
0
OtixPM
0 / 0 / 0
Регистрация: 11.01.2013
Сообщений: 5,483
14.03.2016, 12:48 20
Цитата Сообщение от syrQWIRTY
Код:
port = GPIOA->IDR;
port &= 0xFF00;
port |= som;
GPIOA->ODR = port;Во-первых, для операции с битами ODR читать надо тоже ODR, а не IDR. Так правильнее, даже если результат (в данном случае) одинаков.

Во-вторых, регистр BSRR неспроста задуман таким двухфункциональным. Через него можно одной операцией поменять (как в 1, так и в 0) нужные биты в ODR, при этом остальные биты затронуты не будут. Например, в битах 11...4 выставить значение 0x5A, не затронув биты 15...12 и 3...0:
Код
BSRR = (0x0FF0 << 16) | 0x05A0;
Для своего случая (младший байт ODR, биты 7...0) сами потренируйтесь ;-)
0
14.03.2016, 12:48
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
14.03.2016, 12:48

STM32F103 какова скорость чтения 16-битного слова из флеш?
STM32F103, 72МГц. Размещаю массив констант uint16_t во встроенной памяти....

Конфигурация вывода MCO (ножка PA8) в STM32F103
Доброго времени суток! Несколько раз просматривал даташиты и про конфигурацию...

[Решено]Низкая скорость USB при использовании WinUSB
Разбираюсь с USB в STM32F103. Сделал в контроллере 2 endpoint`a EP1_IN и...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2018, vBulletin Solutions, Inc.
Рейтинг@Mail.ru