вівторок, 29 жовтня 2019 р.

STM32: Використання CCMRAM

Передмова

Почавши експериментувати і навчатись з такою платою на чипі STM32F407VE, я помітив що цей чип має в наявності два банки пам'яті: стандартний SRAM 0x20000000 - 0x20020000, та інший банк пам'яті Core-Coupled-Memory (CCM) 0x10000000 - 0x10010000. Це мене зацікавило і я трішечки почитав і розібрався, що то за пам'ять і як її задіяти в своїх проектах. Бо за замовчуванню вона не задіяна. Як комусь буде ця інформація корисною і стане в нагоді, то буду тільки радий цьому.

Трішки теорії

Деякі мікроконтролери STM32 мають два банки пам'яті: стандартний SRAM та інший банк пам'яті Core-Coupled-Memory (CCM) який може бути швидшим ніж стандартний SRAM, але зазвичай меншого об'єма. Інколи розміщення даних в цей регіон пам'яті може бути вигідним в плані швидкості і економії стандартної пам'яті. Пам'ять CCM під'єднана безпосередньо до шини D-Bus процесора. DMA не має доступу до цієї пам'яті. Тому є можливість розпаралелити дані свого проекту.

Як задіяти

Існує декілька способів. Але я опишу ті способи, що мені підійшли. Я використовую Atolic Truestudio + CubeMX і все що описано нижче - випробувано на цій IDE з генератором коду ініціалізації. Як на інших IDE буде, я не в курсі. Певен, що і на CubeIDE буде працювати все так само, бо є нащадком Atolic Truestudio з інтегрованим CubeMX.

Розміщення всіх ініціалізованих даних у CCM:

У вашому проекті буде файл з розширенням *.ld, наприклад, STM32F407VE_FLASH.ld. Відкрийте його на редагування та зробіть такі зміни в кінці секції ".data":
} >RAM AT> FLASH
На такий рядок:
} >CCMRAM AT> FLASH

Розміщення всіх нульових ініціалізованих даних у CCM:

У вашому проекті буде файл з розширенням "*.ld", наприклад, "STM32F407VE_FLASH.ld". Відкрийте його на редагування та зробіть такі зміни в кінці секції ".bss":
} >RAM
На такий рядок:
} >CCMRAM

Розміщення окремих не ініціалізованих змінних у CCM:

Ви можете дуже просто помістити не ініціалізовані змінні в CCM, додаючи до їх оголошення атрібут розділу CCMRAM. Наприклад масив "array_in_ccm" з 1024 байт даних типу "char":
char array_in_ccm[1024] __attribute__((section(".ccmram")));
Або таким чином:
__attribute__((section(".ccmram"))) char array_in_ccm[1024];
А зробивши перевизначення на початку файлу:
#define CCMRAM __attribute__((section(".ccmram")))
Можна оголошувати не ініціалізовані дані вже таким чином:
CCMRAM char array_in_ccm[1024];
Або так:
char array_in_ccm[1024] CCMRAM;
Щоб це працювало, перевірте наявність секції ".ccmram" в скрипті "STM32F407VE_FLASH.ld". За відсутності цієї секції - додайте:
/* CCM-RAM section 
  * 
  * IMPORTANT NOTE! 
  * If initialized variables will be placed in this section,
  * the startup code needs to be modified to copy the init-values.  
  */
  .ccmram :
  {
    . = ALIGN(4);
    _sccmram = .;       /* create a global symbol at ccmram start */
    *(.ccmram)
    *(.ccmram*)
    
    . = ALIGN(4);
    _eccmram = .;       /* create a global symbol at ccmram end */
  } >CCMRAM
Але будьте обережні, щоб не ініціалізувати змінну навіть з нулем. Оскільки це займе місце у FLASH.

Розміщення окремих ініціалізованих змінних у CCM:

І навпаки, ви можете створити ініціалізовані дані в розділі CCMRAM переконавшись що в скрипті "STM32F407VE_FLASH.ld" присутній такий запис:
 _siccmram = LOADADDR(.ccmram);

  /* CCM-RAM section 
  * 
  * IMPORTANT NOTE! 
  * If initialized variables will be placed in this section,
  * the startup code needs to be modified to copy the init-values.  
  */
  .ccmram :
  {
    . = ALIGN(4);
    _sccmram = .;       /* create a global symbol at ccmram start */
    *(.ccmram)
    *(.ccmram*)
    
    . = ALIGN(4);
    _eccmram = .;       /* create a global symbol at ccmram end */
  } >CCMRAM AT> FLASH
Секція CCM-RAM в такому вигляді, дозволяє оголошувати і ініціалізовані дані, наприклад:
char array_in_ccm[1024] CCMRAM = {0,1,2,3,4,5,6,7,8,9,0};
Або так:
CCMRAM char array_in_ccm[1024] = {0,1,2,3,4,5,6,7,8,9,0};
Масив даних розташувався в пам'яті CCM:
Зазначу, що використовуючи Atolic TrueStudio разом з CubeMX, в скрипті "STM32F407VE_FLASH.ld" секція, для розміщення ініціалізованих змінних в пам'ять CCM, вже була в наявності. І додавати чи правити нічого не знадобилось. Достатньо додати атрибут "__attribute__((section(".ccmram")))" до змінної для розміщення певних ініціалізованих даних до розділу пам'яті CCM.

Джерело знань тут, або де інде. Шукайте, читайте, експериментуйте. 

середу, 23 жовтня 2019 р.

STM32: Бібліотека touchscreen XPT2046 по шині SPI


Передмова

В попередній статті "Бібліотека дисплею ILI9341 по інтерфейсу FSMC" розібрались як виводити зображення на екран дисплею. А в цій статті обговоримо, як зчитувати координати сенсорної панелі при натисканні на неї.
Цей дисплей оснащено резистивним touchscreen який обслуговує контролер XPT2046 або ADS7843. Цей контролер є 12 бітним дискретизатором аналогово-цифрового перетворювача, при натисканні на панель, зчитує напругу по координатам X, Y. Значення напруги перетворює за допомоги АЦП в дискретні значення, та виставляє сигнал готовності даних. По синхронному послідовному інтерфейсу (SPI) можемо запросити дискретні значення координат X та Y зі швидкістю 1.5 - 2.5 Mbits/sec.

CubeMX

За основу візьмемо проект з попередньої статті. Згідно схеми, сенсорну панель підключено до SPI2 мікроконтролеру, де T_SCK - PB13, T_MISO - PB14, T_MOSI - PB15, сигнал чип-селект T_CS - PB12, а сигнал готовності даних при натисканні T_IRQ (T_PEN) - PC5 (виділено червоним):
Схема підключення touchscreen
Завантажимо до CubeMX проект з попередньої статті. В мене це "STM32F407VE_Black_ILI9341.ioc", робимо потрібні налаштування та зберігаємо з іншим ім'ям, як окремий проект.

Налаштування для роботи з touchscreen

Налаштування SPI:

Налаштування SPI
  1. В розділі "Connectivity" обираємо SPI2;
  2. Mode -> Full-Duplex Master;
  3. Prescaller -> 32 (можна спробувати 16), щоб Baud Rate було 1.3125 Mbits/s (2.625 Mbits/s);
  4. Перевірте щоб SPI2 був на шпильках як зазначено на малюнку.

Налаштування GPIO для Chip Select:

Налаштування T_CS
  1. В розділі "System Core" обираємо GPIO;
  2. Тиснемо на PB12;
  3. Налаштовуємо як на малюнку GPIO output level -> High, GPIO mode -> Output Push Pull, GPIO Pull-up, Maximum output speed -> High, User Label -> T_CS;
  4. Перевіряємо щоб назва PB12 була T_CS.

Налаштування GPIO для T_IRQ:

Налаштування T_IRQ
  1. В розділі "System Core" обираємо GPIO;
  2. Тиснемо на PC5;
  3. Налаштовуємо як на малюнку. GPIO mode -> External Interrupt Mode with Rising/Falling edge trigger detection, GPIO Pull-up, User Label -> T_IRQ;
  4. Перевіряємо щоб назва PC5 була T_IRQ.

Налаштування переривання від шпильки T_IRQ:

Налаштування переривань

  1. В розділі "System Core" обираємо NVIC;
  2. Позначаємо "галочкою" (checkbox) "EXTI line [9:5] interrupts".
Налаштування FSMC залишаємо як є з попередньої статті. Або, як проект створили новий, то налаштовуємо, як в статті "STM32: Бібліотека дисплею ILI9341 по інтерфейсу FSMC".

Зберігаємо проект, та генеруємо код проекту. Відкриваємо чи експортуємо проект до свого засобу розробки.

Бібліотека touch screen

Взяв за основу бібліотеку у користувача github . Виправив одну помилку, а так залишив як є. Оригінал бібліотеки за ланкою. Ланка на мою бібліотеку touchscreen. Бібліотека складається з двох файлів XPT2046_touch.h та XPT2046_touch.c 

Налаштування бібліотеки:

#define XPT2046_SPI_PORT hspi2
extern SPI_HandleTypeDef XPT2046_TOUCH_SPI_PORT;

#define XPT2046_IRQ_Pin       T_IRQ_Pin
#define XPT2046_IRQ_GPIO_Port T_IRQ_GPIO_Port
#define XPT2046_CS_Pin        T_CS_Pin
#define XPT2046_CS_GPIO_Port  T_CS_GPIO_Port

// change depending on screen orientation
#define XPT2046_SCALE_X 240
#define XPT2046_SCALE_Y 320

// to calibrate uncomment UART_Printf line in ili9341_touch.c
#define XPT2046_MIN_RAW_X 3400
#define XPT2046_MAX_RAW_X 29000
#define XPT2046_MIN_RAW_Y 3300
#define XPT2046_MAX_RAW_Y 30000
  1. Назначаємо на якому SPI "сидить" touch панель;
  2. Назначаємо порт і номер шпильки де під'єднано сигнали chip select та сигнал переривання про готовність даних (T_CS, T_IRQ);
  3. Задаємо розподільну здатність екрану по X та Y;
  4. Калібровочні значення touch панелі.
Якщо ви створили проект за допомоги CubeMX, як зазначено вище, то налаштування бібліотеки залишаються як є і додаткових налаштувань не потребує.

Додайте файли бібліотеки до свого проекту. Відкрийте файл "main.c" та додайте рядок:
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "XPT2046_touch.h"
/* USER CODE END Includes */
Спробуйте зкомпілювати проект. Як немає помилок, спробуємо щось намалювати за допомоги touch screen.

Малюємо за допомоги touch screen

Щоб можна було малювати на дисплеї ILI9341 додайте до проекту файли бібліотеки дисплею ILI9341, як зазначено в попередній статті. Це тека inc та src.

Додайте до коду в файл "main.c" проекту рядок з вкладенням файлу бібліотеки дисплея:
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "ili9341.h"
#include "XPT2046_touch.h"
/* USER CODE END Includes */
Спробуйте зкомпілювати проект. Як немає помилок, йдемо далі.

Додайте до коду в файл "main.c" в користувацьку секцію 2 такий код:
/* USER CODE BEGIN 2 */
  lcdBacklightOn();
  lcdInit();
  lcdSetOrientation(LCD_ORIENTATION_PORTRAIT);
  lcdFillRGB(COLOR_BLACK);
  /* USER CODE END 2 */
Вмикаємо підсвітку екрану, ініціалізуємо дисплей, задаємо орієнтацію дисплею, очищаємо дисплей чорним кольором.

В користувацьку секцію 4 файлу "main.c"додайте callback функцію:
void HAL_GPIO_EXTI_Callback (uint16_t GPIO_Pin)
{
 if (GPIO_Pin == T_IRQ_Pin)
 {
  if(XPT2046_TouchPressed())
  {
   uint16_t x = 0, y = 0;
   if(XPT2046_TouchGetCoordinates(&x, &y))
   {
    lcdFillCircle((lcdGetWidth() - x), y, 2, COLOR_GREENYELLOW);
   }
  }

 }
}
До цієї функції мікроконтролер буде потрапляти кожного разу коли ви будете натискати (малювати) на touch панелі. Тут буде перевірятись чи натиснуто на панель, і якщо так, то будуть братись координати натискання, та по цим координатам намалюємо маленьке зафарбоване коло жовто-зеленого кольору.

Компілюйте, заливайте і малюйте.

Приклад роботи

Приклад роботи

Відео