STM32F4Discovery – свържете камерата чрез DCMI интерфейс. Информационен портал за сигурност Stm32 камера от мобилен телефон

  • Урок

STM32F4Discovery – свържете камерата чрез DCMI интерфейс

Имало едно време свързване на камера от мобилен телефон към микроконтролер STM32F407VGT6(което се провежда на дъската STM32F4Discovery), дори не се замислих за факта, че този контролер има специален хардуерен интерфейс за този въпрос. Може би не съм чел внимателно листа с данни, но винаги съм мислил, че интерфейсът DCMIпредлага се само за чипове в пакети UFBGA176и LQFPот 144 фута. Но не толкова отдавна открих озвучената подробност: 100 крака STM32F407също има DCMI на борда.
Като голям фен на изучаването и съвместното пускане на различни мобилни хардуери (по-специално LCD дисплеи и камери) с MK, просто не можех да подмина такова откритие и реших да запълня тази празнина в изследването на STM32 периферни устройства. Всъщност този материал е посветен на описанието на изпълнението на възникналата идея.

Само малко теория.

На първо място, трябва да си представите за какво говорим - или по-скоро какво е CMOS камера и с какво се използва.
Този тип камера извежда информация от сензора в цифров вид: RGB, YCbCr, а също и в компресиран вид - JPEG. Различните камери имат свои собствени нюанси по отношение на възможностите, ще разгледам много специфичен случай на камера с ниска разделителна способност (VGA, 640x480), която извадих от телефона си в древни времена " Siemens C72“ (сензор PixelPlus PO2030N). Тази камера е най-подходяща за изследване поради лекотата на работа и принадлежността си към повече или по-малко разпространен тип. Преди много време направих малка платка за него (за по-лесно свързване) - със стабилизатор 2,8 V и издърпващи резистори на шината I2C. Ето го (кабелът и конекторът на камерата са скрити под корпуса).

В допълнение към нюансите в областта на формата на данните, камерите могат да се различават и по броя на щифтовете за синхронизация. Повечето (по мое мнение) сензори имат специални щифтове за хоризонтална и вертикална синхронизация; но има фотоапарати, които имат само пикселен строб изход и те ви уведомяват за началото на нов ред/кадър, използвайки специални предадени кодове (напр. 0x00или 0xFF). Камерата, която имам, има външни щифтове за синхронизация.
Можете да оцените приблизително схематично представяне на камерата под формата на блок.

В по-голямата си част CMOS камерите се управляват чрез интерфейс I2C(въпреки че съм виждал устройства, управлявани от UART). Чрез I2C се конфигурират различни параметри, като разделителна способност, цветова гама, формат на изходните данни и др.
Заключение EXTCLK– клокване на камерата, което трябва да се осигури външно. DCLK– стробиращ сигнал, по предния или заден фронт на който се записват данни в шината за данни на камерата (например байт данни на един пиксел от матрицата или байт данни „половин пиксел“, ако камерата работи в RGB565). HSYNC– сигнал за хоризонтална синхронизация, указващ началото на нов ред, и VSYNC– сигнал за синхронизация, чието активно ниво показва началото на нов кадър. Изводи D0..D7– шина за данни; Като правило, за такива камери е осем бита.
Сега нека поговорим повече за сигналите за синхронизация.

Графиките показват, че камерата е конфигурирана за сигнална активност DCLKсамо по време на активната фаза HSYNC(именно тази фаза ни интересува; часовниковият сигнал по време на периода на „подаване на линия“ не ни интересува). Ако камерата е настроена на резолюция 320x240, тогава по време на всеки импулс HSYNC 320 импулса пасват DCLK, и през периода VSYNC – 240 HSYNC.
Когато увеличим мащаба, виждаме какво се случва в шината за данни.

При нарастващ фронт (в този случай) байт се премахва от шината за данни, който може да бъде изпратен директно към дисплея за показване или „сгънат“ в буфер за последваща обработка.

На теория всичко е повече или по-малко ясно, сега за интерфейса DCMIмикроконтролер STM32.

Интерфейс DCMIможе да работи с шина за данни с ширина до 14 бита, поддържа хардуерна и софтуерна синхронизация, както и формати на данни: YCbCr, RGB и JPEG.
освен това DCMIсъдържа буфер FIFO, има възможност за конфигуриране на прекъсвания (включително при попълване на регистъра с данни) и конфигуриране на работа чрез DMA.

Прекъсвания от DCMIможе да бъде извикан, когато възникнат следните условия: край на линия, край на рамка, препълване на буфера за получаване, открита грешка при синхронизиране (с вътрешна синхронизация).
Бях донякъде объркан от липсата на специален изход за часовник на камерата. Не знам защо разработчиците от SGS MicroelectronicsБеше изоставен, но за мен би било много удобно да имам например персонализиран източник на часовник.
Лично аз използвах таймер-брояч с общо предназначение, включен в режим PWM, за да генерирам квадратна вълна с честота 4 MHz. Разбира се, не можете да получите висок FPS с такъв часовник, но ще направя резервация веднага - дисплеят, който използвам, не е свързан с FSMC, следователно най-дългата функция в цялата верига е функцията за извеждане на LCD, следователно при по-висока честота извеждането на изображението на екрана се проваля. Затова преди разтоварване изключвам таймера и след него го включвам отново.
Хардуерен модул DCMIсъдържа, в допълнение към регистъра на данните, десет регистъра за управление/статус. Това е: контролен регистър ( DCMI_CR), регистър на състоянието ( DCMI_SR), регистър на състоянието на прекъсване ( DCMI_RIS), регистър за разрешаване на прекъсване ( DCMI_IER), регистър на маската за прекъсване ( DCMI_MIS), регистър за нулиране на флаг за прекъсване ( DCMI_ICR), регистър на вътрешния часовник ( DCMI_ESCR), вътрешен регистър за нулиране на маската на кода на часовника ( DCMI_ESUR), регистър на началните стойности при заснемане на част от кадъра ( DCMI_CWSTRT) и регистър на размера на фрагмента на рамката в режим CropWindow ( DCMI_CWSIZE). И, разбира се, регистърът на данните - DCMI_DR.
В този случай регистрите, свързани с улавянето на част от кадъра и вътрешната синхронизация, не ни интересуват. Също така реших да оставя прекъсванията сами засега, така че си струва да разгледаме по-подробно само контролния регистър DCMI_CRи регистър на състоянието DCMI_SR.

Контролният регистър ни дава възможност напълно да персонализираме формата на взаимодействие с камерата: размер на шината за данни, нива на активна линия HSYNCи VSYNCи т.н.

По ред. малко АКТИВИРАНЕ– разбира се, че интерфейсът е пуснат в действие. Поле EDM (разширен режим на данни) – размер на шината за данни; Моят фотоапарат има осем-битова шина, така че това поле трябва да бъде зададено на „00“. Поле FCRC (контрол на скоростта на заснемане на кадри) дава възможност за леко регулиране на FPC: 00 – всички входящи кадри се улавят, 01 – всеки втори кадър, 10 – всеки четвърти. битове VSPOLи HSPOL– активни нива на вертикални и хоризонтални линии за синхронизация. Активните нива се игнорират и не се улавят данни по време на активни периоди, това трябва да се вземе предвид. PCKPOL– бит от активното ниво на стробоскопа на пиксела – по кой край на сигнала да се четат данни от шината: отпред или отзад. ESS– бит за избор на метод на синхронизация: външна или вътрешна. JPEG– избор на формат на входящи данни – компресиран или не. КРОП– бит за избор на улавяне на фрагмент от рамка ( прозорец за изрязване). Ако този бит е зададен на единица, интерфейсът ще улавя данни в прозорец, определен от стойностите в регистрите DCMI_CWSTRTи DCMI_CWSIZE.

И така, нека го настроим.
Тъй като съм свикнал да използвам стандартната периферна библиотека от ST (въпреки че в първите итерации на работа с нови периферни устройства никога не я използвам, докато не се занимавам ръчно с регистрите), настройвам настройките с помощта на библиотеката.

Void DCMIInitialRoutine(void) ( DCMI_InitTypeDef DCMI_CamType; DCMI_DeInit(); DCMI_CamType.DCMI_CaptureMode = DCMI_CaptureMode_Continuous; DCMI_CamType.DCMI_CaptureRate = DCMI_CaptureRate_All_Frame; DCMI_CamType .DCMI_ExtendedDataMode_8b; DCMI_SynchroMode = DCMI_CamType(ENABLE);
Всъщност за моите нужди беше възможно да не пипам нито един бит в регистъра DCMI_CR– по подразбиране се нулират – с изключение на битовете УЛАВЯНЕи АКТИВИРАНЕ.
Интерфейсът е конфигуриран и готов за използване. След изпращане на часовников сигнал към камерата, интерфейсът ще започне да получава данните, които трябва да обработим.
Като начало си поставих най-простата задача - да изведа изображението на дисплея, така че обработката на данните да бъде минимална.
Регистърът на състоянието ще ни помогне при навременното четене на данни от приемащия буфер DCMI_SR.

Много оскъден брой битове са достъпни за четене - само три. битове HSYNCи VSYNCсигнализира състоянието на съответните линии: активна фаза или подаване на линия; най-интересното е малкото FNE. Той ни казва да запълним буфера с данни. Или за непопълване.
Проверка на състоянието на бита в стандартен цикъл FNE V DCMI_SR, научаваме за пристигането на данни в приемащия тридесет и две битов буфер. В моя случай данните ще бъдат разположени така:

При настройка на бит FNEв регистъра на състоянието DCMI_SRполучаващият буфер ще съдържа четири байта, данни от два съседни пиксела: Байт0 и Байт1 – 16 пикселни бита п, А Байт2 и Байт3 – 16 пикселни бита n+1. Всичко, което трябва да направя, е да ги комбинирам и да ги изпратя на дисплея. И така, ето как изглежда основният цикъл:
while (1) ( while ((DCMI_GetFlagStatus(DCMI_FLAG_FNE)) == RESET); //Изчакване на буфера TIM_Cmd(TIM3, DISABLE); //Деактивиране на CAM часовника cam_grab = (DCMI->DR); //Четене на буфер SendDataByte_LCD (cam_grab); //Четене на 2-ра част от буфера SendDataByte_LCD (cam_grab)
Тоест чакам да се сложи битът FNEв регистъра на състоянието DCMI_SRи след това качвам 16 бита данни на дисплея в две стъпки.
В този момент бих искал да стигна до логично заключение, но това не трябваше да бъде.
След флашване на фърмуера и рестартиране на MK, видях на дисплея... не, видях собствената си много позната физика, но в черни и сини нюанси. Червеният и зеленият цвят липсваха напълно.
След кратък преглед с дебъгера беше открито следното: регистърът на данните на интерфейса съдържаше само 16 бита данни на пиксел, като долните 8 бита бяха разположени на място Байт0 (вижте фигурата по-горе), а старейшините са на мястото си Байт2 . Пространства Байт1 и Байт3 бяха празни. До сега не разбрах откъде идва това разминаване между документацията и реалността и може би ще се обърна към СТМ.
В резултат на това успяхме да получим изображение от камерата с помощта на интерфейса DCMI, макар и не без известни трудности. На фигурата показвам снимка на дисплея, на който се показва изображението на демонстрационната платка STM32F3Discoveryот камерата ми.

Ето какво ще видим в заключенията: EXTCLK, PIXCK, HSYNCи VSYNC, ако свържете логически анализатор.

Всичко изглежда точно както се очаква: 240 импулса HSYNCсе вписва в продължителността на един VSYNC, 320 PIXCK- в едно HSYNC. По време на активната фаза HSYNCкамерата не дава сигнали PIXCK– точно така, както беше устроена.
Като цяло интерфейсът донякъде ме разочарова. Липсата на „стандартен“ тактов крак на камерата, липсата на някакви повече или по-малко интересни вградени функции (какво ще кажете за хардуерен JPEG енкодер?) И дори танци с тамбурина около полупечен FIFO
Организиране на операторска работа по време на прекъсвания PIXCK, HSYNCи VSYNCНямах толкова проблеми, колкото при работата с камерата с помощта на хардуер DCMI.
В близко бъдеще обаче ще се опитам да заснема кадър и да го компресирам JPEGи опитайте да запишете снимка на SD картата.
PS. За всеки случай давам линк към проекта за " Код :: Блокове"- изведнъж ще бъде полезно за някого.

Картата се свързва чрез две функции:
1. Използване на функцията disk_initializeкартата се инициализира.
2. След това трябва да го монтирате f_mount.

След като завършите успешно тези стъпки, можете да извършвате различни операции с картата, като например:
1. f_open– отваряне на файл,
2. f_close– затваряне на файла;
3. f_mkdir– създаване на директория;
4. f_chdir– избор на директория;
5. f_write– запис във файл;
6. f_read– четене от файла.

Описах работата с камерата и SD картата, сега нека да разгледаме как работи програмата като цяло:
1. Инициализирайте SD картата;
2. Инициализирайте модула на камерата;
3. Отворете файла time.txt (файлът трябва да съдържа един ред от формата 01.01.2014_12:00 ), който съхранява времето за отчитане на RTC таймера;
4. Прочетете часа и датата от файла и настройте RTC;
5. Затворете файла time.txt;
6. Създайте директория за съхранение на снимки “LinkSpritePhoto”;
7. Когато натиснете бутона PA0 на таблото, направете снимка и я запазете на картата (Докато се прави снимката, синият светодиод свети);
8. Ако някоя от функциите не се изпълнява, попадаме в безкраен цикъл и светва зеленият светодиод.

За да стартирате камерата в непрекъснат режим, трябва да откоментирате следните редове в main.c:

//EnabledButtonStart = 101; // За да работите в цикъл, разкоментирайте този ред //Delay(300); // Забавяне за стартиране в цикъл
И коментирайте този ред:

EnabledButtonStart = 0; // За да работите в цикъл, коментирайте този ред
След това, когато го включите, камерата ще започне непрекъснато да прави снимки.

Като цяло съставих описание на това как работи тази камера и сега мога да покажа резултата от работата.

Имало едно време свързване на камера от мобилен телефон към микроконтролер STM32F407VGT6(което се провежда на дъската STM32F4Discovery), дори не се замислих за факта, че този контролер има специален хардуерен интерфейс за този въпрос. Може би не съм чел внимателно листа с данни, но винаги съм мислил, че интерфейсът DCMIпредлага се само за чипове в пакети UFBGA176и LQFPот 144 фута. Но не толкова отдавна открих озвучената подробност: 100 крака STM32F407също има DCMI на борда.
Като голям фен на изучаването и съвместното пускане на различни мобилни хардуери (по-специално LCD дисплеи и камери) с MK, просто не можех да подмина такова откритие и реших да запълня тази празнина в изследването на STM32 периферни устройства. Всъщност този материал е посветен на описанието на изпълнението на възникналата идея.

Само малко теория.

На първо място, трябва да си представите за какво говорим - или по-скоро какво е CMOS камера и с какво се използва.
Този тип камера извежда информация от сензора в цифров вид: RGB, YCbCr, а също и в компресиран вид - JPEG. Различните камери имат свои собствени нюанси по отношение на възможностите, ще разгледам много специфичен случай на камера с ниска разделителна способност (VGA, 640x480), която извадих от телефона си в древни времена " Siemens C72“ (сензор PixelPlus PO2030N). Тази камера е най-подходяща за изследване поради лекотата на работа и принадлежността си към повече или по-малко разпространен тип. Преди много време направих малка платка за него (за по-лесно свързване) - със стабилизатор 2,8 V и издърпващи резистори на шината I2C. Ето го (кабелът и конекторът на камерата са скрити под корпуса).


В допълнение към нюансите в областта на формата на данните, камерите могат да се различават и по броя на щифтовете за синхронизация. Повечето (по мое мнение) сензори имат специални щифтове за хоризонтална и вертикална синхронизация; но има фотоапарати, които имат само пикселен строб изход и те ви уведомяват за началото на нов ред/кадър, използвайки специални предадени кодове (напр. 0x00или 0xFF). Камерата, която имам, има външни щифтове за синхронизация.
Можете да оцените приблизително схематично представяне на камерата под формата на блок.


В по-голямата си част CMOS камерите се управляват чрез интерфейс I2C(въпреки че съм виждал устройства, управлявани от UART). Чрез I2C се конфигурират различни параметри, като разделителна способност, цветова гама, формат на изходните данни и др.
Заключение EXTCLK– клокване на камерата, което трябва да се осигури външно. DCLK– стробиращ сигнал, по предния или заден фронт на който се записват данни в шината за данни на камерата (например байт данни на един пиксел от матрицата или байт данни „половин пиксел“, ако камерата работи в RGB565). HSYNC– сигнал за хоризонтална синхронизация, указващ началото на нов ред, и VSYNC– сигнал за синхронизация, чието активно ниво показва началото на нов кадър. Изводи D0..D7– шина за данни; Като правило, за такива камери е осем бита.
Сега нека поговорим повече за сигналите за синхронизация.


Графиките показват, че камерата е конфигурирана за сигнална активност DCLKсамо по време на активната фаза HSYNC(именно тази фаза ни интересува; часовниковият сигнал по време на периода на „подаване на линия“ не ни интересува). Ако камерата е настроена на резолюция 320x240, тогава по време на всеки импулс HSYNC 320 импулса пасват DCLK, и през периода VSYNC – 240 HSYNC.
Когато увеличим мащаба, виждаме какво се случва в шината за данни.


При нарастващ фронт (в този случай) байт се премахва от шината за данни, който може да бъде изпратен директно към дисплея за показване или „сгънат“ в буфер за последваща обработка.
На теория всичко е повече или по-малко ясно, сега за интерфейса DCMIмикроконтролер STM32.
Интерфейс DCMIможе да работи с шина за данни с ширина до 14 бита, поддържа хардуерна и софтуерна синхронизация, както и формати на данни: YCbCr, RGB и JPEG.
освен това DCMIсъдържа буфер FIFO, има възможност за конфигуриране на прекъсвания (включително при попълване на регистъра с данни) и конфигуриране на работа чрез DMA.


Прекъсвания от DCMIможе да бъде извикан, когато възникнат следните условия: край на линия, край на рамка, препълване на буфера за получаване, открита грешка при синхронизиране (с вътрешна синхронизация).
Бях донякъде объркан от липсата на специален изход за часовник на камерата. Не знам защо разработчиците от SGS MicroelectronicsБеше изоставен, но за мен би било много удобно да имам например персонализиран източник на часовник.
Лично аз използвах таймер-брояч с общо предназначение, включен в режим PWM, за да генерирам квадратна вълна с честота 4 MHz. Разбира се, не можете да получите висок FPS с такъв часовник, но ще направя резервация веднага - дисплеят, който използвам, не е свързан с FSMC, следователно най-дългата функция в цялата верига е функцията за извеждане на LCD, следователно при по-висока честота извеждането на изображението на екрана се проваля. Затова преди разтоварване изключвам таймера и след него го включвам отново.
Хардуерен модул DCMIсъдържа, в допълнение към регистъра на данните, десет регистъра за управление/статус. Това е: контролен регистър ( DCMI_CR), регистър на състоянието ( DCMI_SR), регистър на състоянието на прекъсване ( DCMI_RIS), регистър за разрешаване на прекъсване ( DCMI_IER), регистър на маската за прекъсване ( DCMI_MIS), регистър за нулиране на флаг за прекъсване ( DCMI_ICR), регистър на вътрешния часовник ( DCMI_ESCR), вътрешен регистър за нулиране на маската на кода на часовника ( DCMI_ESUR), регистър на началните стойности при заснемане на част от кадъра ( DCMI_CWSTRT) и регистър на размера на фрагмента на рамката в режим CropWindow ( DCMI_CWSIZE). И, разбира се, регистърът на данните - DCMI_DR.
В този случай регистрите, свързани с улавянето на част от кадъра и вътрешната синхронизация, не ни интересуват. Също така реших да оставя прекъсванията сами засега, така че си струва да разгледаме по-подробно само контролния регистър DCMI_CRи регистър на състоянието DCMI_SR.

Контролният регистър ни дава възможност напълно да персонализираме формата на взаимодействие с камерата: размер на шината за данни, нива на активна линия HSYNCи VSYNCи т.н.


По ред. малко АКТИВИРАНЕ– разбира се, че интерфейсът е пуснат в действие. Поле EDM (разширен режим на данни) – размер на шината за данни; Моят фотоапарат има осем-битова шина, така че това поле трябва да бъде зададено на „00“. Поле FCRC (контрол на скоростта на заснемане на кадри) дава възможност за леко регулиране на FPC: 00 – всички входящи кадри се улавят, 01 – всеки втори кадър, 10 – всеки четвърти. битове VSPOLи HSPOL– активни нива на вертикални и хоризонтални линии за синхронизация. Активните нива се игнорират и не се улавят данни по време на активни периоди, това трябва да се вземе предвид. PCKPOL– бит от активното ниво на стробоскопа на пиксела – по кой край на сигнала да се четат данни от шината: отпред или отзад. ESS– бит за избор на метод на синхронизация: външна или вътрешна. JPEG– избор на формат на входящи данни – компресиран или не. КРОП– бит за избор на улавяне на фрагмент от рамка ( прозорец за изрязване). Ако този бит е зададен на единица, интерфейсът ще улавя данни в прозорец, определен от стойностите в регистрите DCMI_CWSTRTи DCMI_CWSIZE.
И така, нека го настроим. Тъй като съм свикнал да използвам стандартната периферна библиотека от ST (въпреки че в първите итерации на работа с нови периферни устройства никога не я използвам, докато не се занимавам ръчно с регистрите), настройвам настройките с помощта на библиотеката.

Void DCMIInitialRoutine(void) ( DCMI_InitTypeDef DCMI_CamType; DCMI_DeInit(); DCMI_CamType.DCMI_CaptureMode = DCMI_CaptureMode_Continuous; DCMI_CamType.DCMI_CaptureRate = DCMI_CaptureRate_All_Frame; DCMI_CamType .DCMI_ExtendedDataMode_8b; DCMI_SynchroMode = DCMI_CamType(ENABLE);

Всъщност за моите нужди беше възможно да не пипам нито един бит в регистъра DCMI_CR– по подразбиране се нулират – с изключение на битовете УЛАВЯНЕи АКТИВИРАНЕ.
Интерфейсът е конфигуриран и готов за използване. След изпращане на часовников сигнал към камерата, интерфейсът ще започне да получава данните, които трябва да обработим.
Като начало си поставих най-простата задача - да изведа изображението на дисплея, така че обработката на данните да бъде минимална.
Регистърът на състоянието ще ни помогне при навременното четене на данни от приемащия буфер DCMI_SR.

Много оскъден брой битове са достъпни за четене - само три. битове HSYNCи VSYNCсигнализира състоянието на съответните линии: активна фаза или подаване на линия; най-интересното е малкото FNE. Той ни казва да запълним буфера с данни. Или за непопълване.
Проверка на състоянието на бита в стандартен цикъл FNE V DCMI_SR, научаваме за пристигането на данни в приемащия тридесет и две битов буфер. В моя случай данните ще бъдат разположени така:

При настройка на бит FNEв регистъра на състоянието DCMI_SRполучаващият буфер ще съдържа четири байта, данни от два съседни пиксела: Байт0 и Байт1 – 16 пикселни бита п, А Байт2 и Байт3 – 16 пикселни бита n+1. Всичко, което трябва да направя, е да ги комбинирам и да ги изпратя на дисплея. И така, ето как изглежда основният цикъл:

While (1) ( while ((DCMI_GetFlagStatus(DCMI_FLAG_FNE)) == RESET); //Изчакване на буфера TIM_Cmd(TIM3, DISABLE); //Деактивиране на CAM часовника cam_grab = (DCMI->DR); //Четене на буфер SendDataByte_LCD (cam_grab); //Четене на 2-ра част от буфера SendDataByte_LCD (cam_grab)

Тоест чакам да се сложи битът FNEв регистъра на състоянието DCMI_SRи след това качвам 16 бита данни на дисплея в две стъпки.
В този момент бих искал да стигна до логично заключение, но това не трябваше да бъде.
След флашване на фърмуера и рестартиране на MK, видях на дисплея... не, видях собствената си много позната физика, но в черни и сини нюанси. Червеният и зеленият цвят липсваха напълно.
След кратък преглед с дебъгера беше открито следното: регистърът на данните на интерфейса съдържаше само 16 бита данни на пиксел, като долните 8 бита бяха разположени на място Байт0 (вижте фигурата по-горе), а старейшините са на мястото си Байт2 . Пространства Байт1 и Байт3 бяха празни. До сега не разбрах откъде идва това разминаване между документацията и реалността и може би ще се обърна към СТМ.
В резултат на това успяхме да получим изображение от камерата с помощта на интерфейса DCMI, макар и не без известни трудности. На фигурата показвам снимка на дисплея, на който се показва изображението на демонстрационната платка STM32F3Discoveryот камерата ми.


Ето какво ще видим в заключенията: EXTCLK, PIXCK, HSYNCи VSYNC, ако свържете логически анализатор.


Всичко изглежда точно както се очаква: 240 импулса HSYNCсе вписва в продължителността на един VSYNC, 320 PIXCK- в едно HSYNC. По време на активната фаза HSYNCкамерата не дава сигнали PIXCK– точно така, както беше устроена.
Като цяло интерфейсът донякъде ме разочарова. Липсата на „стандартен“ тактов крак на камерата, липсата на някакви повече или по-малко интересни вградени функции (какво ще кажете за хардуерен JPEG енкодер?) И дори танци с тамбурина около полупечен FIFO
Организиране на операторска работа по време на прекъсвания PIXCK, HSYNCи VSYNCНямах толкова проблеми, колкото при работата с камерата с помощта на хардуер DCMI.
В близко бъдеще обаче ще се опитам да заснема кадър и да го компресирам JPEGи опитайте да запишете снимка на SD картата.
PS. За всеки случай давам линк към проекта за " Код :: Блокове"- изведнъж ще бъде полезно за някого.

Или заснемането на забавен каданс е заснемане с честота, по-ниска от стандартната честота на снимане и прожектиране от 24 кадъра в секунда.

След като започнах да изучавам микроконтролери STM32 и написах „HelloWorld“ с мигащ светодиод, разбрах, че за да разбера по-добре работата на STM32, трябваше да внедря нещо по-сложно, използвайки повече периферни устройства на микроконтролера. Така се роди идеята за създаване на Time-lapse камера.

Камерата, която разработих, ще прави снимки приблизително веднъж на всеки 5 секунди и ще ги записва на SD картата в jpeg формат. След това те трябва да бъдат комбинирани на компютъра във видео файл.

За да създам камерата, използвах следните компоненти:

Картата се свързва чрез две функции:
1. Използване на функцията disk_initializeкартата се инициализира.
2. След това трябва да го монтирате f_mount.

След като завършите успешно тези стъпки, можете да извършвате различни операции с картата, като например:
1. f_open– отваряне на файл,
2. f_close– затваряне на файла;
3. f_mkdir– създаване на директория;
4. f_chdir– избор на директория;
5. f_write– запис във файл;
6. f_read– четене от файла.

Описах работата с камерата и SD картата, сега нека да разгледаме как работи програмата като цяло:
1. Инициализирайте SD картата;
2. Инициализирайте модула на камерата;
3. Отворете файла time.txt (файлът трябва да съдържа един ред от формата 01.01.2014_12:00 ), който съхранява времето за отчитане на RTC таймера;
4. Прочетете часа и датата от файла и настройте RTC;
5. Затворете файла time.txt;
6. Създайте директория за съхранение на снимки “LinkSpritePhoto”;
7. Когато натиснете бутона PA0 на таблото, направете снимка и я запазете на картата (Докато се прави снимката, синият светодиод свети);
8. Ако някоя от функциите не се изпълнява, попадаме в безкраен цикъл и светва зеленият светодиод.

За да стартирате камерата в непрекъснат режим, трябва да откоментирате следните редове в main.c:

//EnabledButtonStart = 101; // За да работите в цикъл, разкоментирайте този ред //Delay(300); // Забавяне за стартиране в цикъл
И коментирайте този ред:

EnabledButtonStart = 0; // За да работите в цикъл, коментирайте този ред
След това, когато го включите, камерата ще започне непрекъснато да прави снимки.

Като цяло съставих описание на това как работи тази камера и сега мога да покажа резултата от работата.

  • Урок

STM32F4Discovery – свържете камерата чрез DCMI интерфейс

Имало едно време свързване на камера от мобилен телефон към микроконтролер STM32F407VGT6(което се провежда на дъската STM32F4Discovery), дори не се замислих за факта, че този контролер има специален хардуерен интерфейс за този въпрос. Може би не съм чел внимателно листа с данни, но винаги съм мислил, че интерфейсът DCMIпредлага се само за чипове в пакети UFBGA176и LQFPот 144 фута. Но не толкова отдавна открих озвучената подробност: 100 крака STM32F407също има DCMI на борда.
Като голям фен на изучаването и съвместното пускане на различни мобилни хардуери (по-специално LCD дисплеи и камери) с MK, просто не можех да подмина такова откритие и реших да запълня тази празнина в изследването на STM32 периферни устройства. Всъщност този материал е посветен на описанието на изпълнението на възникналата идея.

Само малко теория.

На първо място, трябва да си представите за какво говорим - или по-скоро какво е CMOS камера и с какво се използва.
Този тип камера извежда информация от сензора в цифров вид: RGB, YCbCr, а също и в компресиран вид - JPEG. Различните камери имат свои собствени нюанси по отношение на възможностите, ще разгледам много специфичен случай на камера с ниска разделителна способност (VGA, 640x480), която извадих от телефона си в древни времена " Siemens C72“ (сензор PixelPlus PO2030N). Тази камера е най-подходяща за изследване поради лекотата на работа и принадлежността си към повече или по-малко разпространен тип. Преди много време направих малка платка за него (за по-лесно свързване) - със стабилизатор 2,8 V и издърпващи резистори на шината I2C. Ето го (кабелът и конекторът на камерата са скрити под корпуса).

В допълнение към нюансите в областта на формата на данните, камерите могат да се различават и по броя на щифтовете за синхронизация. Повечето (по мое мнение) сензори имат специални щифтове за хоризонтална и вертикална синхронизация; но има фотоапарати, които имат само пикселен строб изход и те ви уведомяват за началото на нов ред/кадър, използвайки специални предадени кодове (напр. 0x00или 0xFF). Камерата, която имам, има външни щифтове за синхронизация.
Можете да оцените приблизително схематично представяне на камерата под формата на блок.

В по-голямата си част CMOS камерите се управляват чрез интерфейс I2C(въпреки че съм виждал устройства, управлявани от UART). Чрез I2C се конфигурират различни параметри, като разделителна способност, цветова гама, формат на изходните данни и др.
Заключение EXTCLK– клокване на камерата, което трябва да се осигури външно. DCLK– стробиращ сигнал, по предния или заден фронт на който се записват данни в шината за данни на камерата (например байт данни на един пиксел от матрицата или байт данни „половин пиксел“, ако камерата работи в RGB565). HSYNC– сигнал за хоризонтална синхронизация, указващ началото на нов ред, и VSYNC– сигнал за синхронизация, чието активно ниво показва началото на нов кадър. Изводи D0..D7– шина за данни; Като правило, за такива камери е осем бита.
Сега нека поговорим повече за сигналите за синхронизация.

Графиките показват, че камерата е конфигурирана за сигнална активност DCLKсамо по време на активната фаза HSYNC(именно тази фаза ни интересува; часовниковият сигнал по време на периода на „подаване на линия“ не ни интересува). Ако камерата е настроена на резолюция 320x240, тогава по време на всеки импулс HSYNC 320 импулса пасват DCLK, и през периода VSYNC – 240 HSYNC.
Когато увеличим мащаба, виждаме какво се случва в шината за данни.

При нарастващ фронт (в този случай) байт се премахва от шината за данни, който може да бъде изпратен директно към дисплея за показване или „сгънат“ в буфер за последваща обработка.

На теория всичко е повече или по-малко ясно, сега за интерфейса DCMIмикроконтролер STM32.

Интерфейс DCMIможе да работи с шина за данни с ширина до 14 бита, поддържа хардуерна и софтуерна синхронизация, както и формати на данни: YCbCr, RGB и JPEG.
освен това DCMIсъдържа буфер FIFO, има възможност за конфигуриране на прекъсвания (включително при попълване на регистъра с данни) и конфигуриране на работа чрез DMA.

Прекъсвания от DCMIможе да бъде извикан, когато възникнат следните условия: край на линия, край на рамка, препълване на буфера за получаване, открита грешка при синхронизиране (с вътрешна синхронизация).
Бях донякъде объркан от липсата на специален изход за часовник на камерата. Не знам защо разработчиците от SGS MicroelectronicsБеше изоставен, но за мен би било много удобно да имам например персонализиран източник на часовник.
Лично аз използвах таймер-брояч с общо предназначение, включен в режим PWM, за да генерирам квадратна вълна с честота 4 MHz. Разбира се, не можете да получите висок FPS с такъв часовник, но ще направя резервация веднага - дисплеят, който използвам, не е свързан с FSMC, следователно най-дългата функция в цялата верига е функцията за извеждане на LCD, следователно при по-висока честота извеждането на изображението на екрана се проваля. Затова преди разтоварване изключвам таймера и след него го включвам отново.
Хардуерен модул DCMIсъдържа, в допълнение към регистъра на данните, десет регистъра за управление/статус. Това е: контролен регистър ( DCMI_CR), регистър на състоянието ( DCMI_SR), регистър на състоянието на прекъсване ( DCMI_RIS), регистър за разрешаване на прекъсване ( DCMI_IER), регистър на маската за прекъсване ( DCMI_MIS), регистър за нулиране на флаг за прекъсване ( DCMI_ICR), регистър на вътрешния часовник ( DCMI_ESCR), вътрешен регистър за нулиране на маската на кода на часовника ( DCMI_ESUR), регистър на началните стойности при заснемане на част от кадъра ( DCMI_CWSTRT) и регистър на размера на фрагмента на рамката в режим CropWindow ( DCMI_CWSIZE). И, разбира се, регистърът на данните - DCMI_DR.
В този случай регистрите, свързани с улавянето на част от кадъра и вътрешната синхронизация, не ни интересуват. Също така реших да оставя прекъсванията сами засега, така че си струва да разгледаме по-подробно само контролния регистър DCMI_CRи регистър на състоянието DCMI_SR.

Контролният регистър ни дава възможност напълно да персонализираме формата на взаимодействие с камерата: размер на шината за данни, нива на активна линия HSYNCи VSYNCи т.н.

По ред. малко АКТИВИРАНЕ– разбира се, че интерфейсът е пуснат в действие. Поле EDM (разширен режим на данни) – размер на шината за данни; Моят фотоапарат има осем-битова шина, така че това поле трябва да бъде зададено на „00“. Поле FCRC (контрол на скоростта на заснемане на кадри) дава възможност за леко регулиране на FPC: 00 – всички входящи кадри се улавят, 01 – всеки втори кадър, 10 – всеки четвърти. битове VSPOLи HSPOL– активни нива на вертикални и хоризонтални линии за синхронизация. Активните нива се игнорират и не се улавят данни по време на активни периоди, това трябва да се вземе предвид. PCKPOL– бит от активното ниво на стробоскопа на пиксела – по кой край на сигнала да се четат данни от шината: отпред или отзад. ESS– бит за избор на метод на синхронизация: външна или вътрешна. JPEG– избор на формат на входящи данни – компресиран или не. КРОП– бит за избор на улавяне на фрагмент от рамка ( прозорец за изрязване). Ако този бит е зададен на единица, интерфейсът ще улавя данни в прозорец, определен от стойностите в регистрите DCMI_CWSTRTи DCMI_CWSIZE.

И така, нека го настроим.
Тъй като съм свикнал да използвам стандартната периферна библиотека от ST (въпреки че в първите итерации на работа с нови периферни устройства никога не я използвам, докато не се занимавам ръчно с регистрите), настройвам настройките с помощта на библиотеката.

Void DCMIInitialRoutine(void) ( DCMI_InitTypeDef DCMI_CamType; DCMI_DeInit(); DCMI_CamType.DCMI_CaptureMode = DCMI_CaptureMode_Continuous; DCMI_CamType.DCMI_CaptureRate = DCMI_CaptureRate_All_Frame; DCMI_CamType .DCMI_ExtendedDataMode_8b; DCMI_SynchroMode = DCMI_CamType(ENABLE);
Всъщност за моите нужди беше възможно да не пипам нито един бит в регистъра DCMI_CR– по подразбиране се нулират – с изключение на битовете УЛАВЯНЕи АКТИВИРАНЕ.
Интерфейсът е конфигуриран и готов за използване. След изпращане на часовников сигнал към камерата, интерфейсът ще започне да получава данните, които трябва да обработим.
Като начало си поставих най-простата задача - да изведа изображението на дисплея, така че обработката на данните да бъде минимална.
Регистърът на състоянието ще ни помогне при навременното четене на данни от приемащия буфер DCMI_SR.

Много оскъден брой битове са достъпни за четене - само три. битове HSYNCи VSYNCсигнализира състоянието на съответните линии: активна фаза или подаване на линия; най-интересното е малкото FNE. Той ни казва да запълним буфера с данни. Или за непопълване.
Проверка на състоянието на бита в стандартен цикъл FNE V DCMI_SR, научаваме за пристигането на данни в приемащия тридесет и две битов буфер. В моя случай данните ще бъдат разположени така:

При настройка на бит FNEв регистъра на състоянието DCMI_SRполучаващият буфер ще съдържа четири байта, данни от два съседни пиксела: Байт0 и Байт1 – 16 пикселни бита п, А Байт2 и Байт3 – 16 пикселни бита n+1. Всичко, което трябва да направя, е да ги комбинирам и да ги изпратя на дисплея. И така, ето как изглежда основният цикъл:
while (1) ( while ((DCMI_GetFlagStatus(DCMI_FLAG_FNE)) == RESET); //Изчакване на буфера TIM_Cmd(TIM3, DISABLE); //Деактивиране на CAM часовника cam_grab = (DCMI->DR); //Четене на буфер SendDataByte_LCD (cam_grab); //Четене на 2-ра част от буфера SendDataByte_LCD (cam_grab)
Тоест чакам да се сложи битът FNEв регистъра на състоянието DCMI_SRи след това качвам 16 бита данни на дисплея в две стъпки.
В този момент бих искал да стигна до логично заключение, но това не трябваше да бъде.
След флашване на фърмуера и рестартиране на MK, видях на дисплея... не, видях собствената си много позната физика, но в черни и сини нюанси. Червеният и зеленият цвят липсваха напълно.
След кратък преглед с дебъгера беше открито следното: регистърът на данните на интерфейса съдържаше само 16 бита данни на пиксел, като долните 8 бита бяха разположени на място Байт0 (вижте фигурата по-горе), а старейшините са на мястото си Байт2 . Пространства Байт1 и Байт3 бяха празни. До сега не разбрах откъде идва това разминаване между документацията и реалността и може би ще се обърна към СТМ.
В резултат на това успяхме да получим изображение от камерата с помощта на интерфейса DCMI, макар и не без известни трудности. На фигурата показвам снимка на дисплея, на който се показва изображението на демонстрационната платка STM32F3Discoveryот камерата ми.

Ето какво ще видим в заключенията: EXTCLK, PIXCK, HSYNCи VSYNC, ако свържете логически анализатор.

Всичко изглежда точно както се очаква: 240 импулса HSYNCсе вписва в продължителността на един VSYNC, 320 PIXCK- в едно HSYNC. По време на активната фаза HSYNCкамерата не дава сигнали PIXCK– точно така, както беше устроена.
Като цяло интерфейсът донякъде ме разочарова. Липсата на „стандартен“ тактов крак на камерата, липсата на някакви повече или по-малко интересни вградени функции (какво ще кажете за хардуерен JPEG енкодер?) И дори танци с тамбурина около полупечен FIFO
Организиране на операторска работа по време на прекъсвания PIXCK, HSYNCи VSYNCНямах толкова проблеми, колкото при работата с камерата с помощта на хардуер DCMI.
В близко бъдеще обаче ще се опитам да заснема кадър и да го компресирам JPEGи опитайте да запишете снимка на SD картата.
PS. За всеки случай давам линк към проекта за " Код :: Блокове"- изведнъж ще бъде полезно за някого.



Споделете