|
|
  |
STM32F4, DCMI и USB |
|
|
|
Mar 20 2015, 06:46
|
Гуру
     
Группа: Участник
Сообщений: 2 072
Регистрация: 14-01-06
Пользователь №: 13 164

|
Коллеги, хочу передавать изображения с камеры OV7670 (640x480) на комп. В распоряжении есть плата STM32F4Discovery, камера с ебея уже пересекает китайскую границу, проект использующий аппаратный DCMI и DMА я нашел. Пока суровые китайские таможенники оформляют пересечение камерой границы, хочу хотя бы проэмулировать передачу данных, то есть искусственно заполнять буфер, куда DMA кидает данные тестовой картинкой и принимать ее на компе.
Оговорюсь сразу - задача специфическая, и большого FPS не потребует, 3 кадра в секунду меня устроят.Получается скорость должна составлять около 2 мбайт сек. И что-то я в растерянности. Единственный мой опыт - USB HID на STM32F103, пакетами по 64 байта. Отсюда первый вопрос - в орежиме USB HID какая максимально возможная скорость? 2 мбайт / сек потянет?
Далее -я пытался ковырятьс в примерах - есть там пример, который из платы дисковери делает мышку на акселерометре. Вроде бы это USB HID, но почему-то в тексте программы я встречал упоминание USB OTG. Насколько я знаю, USB HID является ведомым по отношению к компу, а комп - это всегда хост. Вроде бы, если я правильно понял - USB OTG - это разновидность USB Host, плата при этом сама становится "компом" и к ней можно подключать флешку например. Зачем для мышки USB OTG?
В общем, подскажите, что мне нужно для решения задачи?
|
|
|
|
|
Mar 20 2015, 10:48
|
Гуру
     
Группа: Свой
Сообщений: 4 256
Регистрация: 17-02-06
Пользователь №: 14 454

|
Цитата USB OTG - это разновидность USB Host OTG - это и Host и Device. В зависимости от того зажат специальный контакт или нет. То есть это USB которое само определяет куда оно подключилось, если к девайсу, становиться хостом, если к хосту становиться девайсом. То есть OTG не означает что оно использовалось как хост, просто факт возможности Цитата В общем, подскажите, что мне нужно для решения задачи? А для решения задачи вам надо еще драйвер на стороне Windows, есть встроенный HID и практически встроенный CDC. Остальные драйверы надо писать самому, и потому обмен через другие интерфейсы вам создаст дополнительных проблем. Наверное идеологически правильно использовать все же CDC, но в целом можно конечно картинку представить как HID input report, и через interrupt точку гнать данные. Частота пакетов в HID если не ошибаюсь 1 КГц, размер пакета 64 байта максимальный по спецификации для HS, FS и 8 для LS. так что через HID вы продавите 64 Кбайтай/сек - край... Потому смотрите в сторону CDC там скорости повыше
|
|
|
|
|
Mar 20 2015, 17:58
|
Гуру
     
Группа: Участник
Сообщений: 2 072
Регистрация: 14-01-06
Пользователь №: 13 164

|
Установил я virtual comport driver версия 1.4, скачал с самого сайта ST. Все установилось без проблем. Но появляющийся com-порт со значком ошибки - для устройства не установлены драйверы. Хотя номер порту присваивается. При попытке вручную что-то сделать выдается сообщение "Неправильная секция установки службы в этом ini файле" Прошивку качал отсюда http://ctrl-v.biz/blog/7Что я делаю не так? Ini файл прикладываю
Сообщение отредактировал zheka - Mar 20 2015, 18:03
|
|
|
|
|
Mar 21 2015, 14:28
|

Знающий
   
Группа: Свой
Сообщений: 877
Регистрация: 26-01-05
Из: Екатеринбург
Пользователь №: 2 206

|
Цитата(zheka @ Mar 21 2015, 15:15)  Объясните мне феномен - как ни переключаю скорость COM-порта в Terminal - данные идут правильные и на высокой скорости. Это как? Так и есть. В USB данные будут ходить с той скоростью, сколько USB позволит. То, что вы устанавливаете, это фактически настройки для реального COM порта, который может торчать с другой стороны USB. Они уходят отдельными командами и могут быть использованы, если нужно. Например можно сделать конвертер USB-COM и по переданным параметрам устанавливать нужную скорость UART.
--------------------
Пасу котов...
|
|
|
|
|
Mar 22 2015, 05:37
|
Гуру
     
Группа: Участник
Сообщений: 2 072
Регистрация: 14-01-06
Пользователь №: 13 164

|
Нашел что надо прописать. Компилится, линкуется. Но вываливается в Hard Fault.. Ставлю брейкпоинт на самую первую строку - брейкпоинт не срабатывает. В чем моежт быть дело? Файл, выложенный выше, обновил. ///////////////// Прошелся отладчиком пошагово : Код IMPORT __main
LDR R0, =SystemInit BLX R0 LDR R0, =__main BX R0 ENDP доходит до BX R0 и вылетает в hard_fault Стартап я правда взял от примеров от ST для дискавери4, потому как в примере для Eclipse он как будто на другом языке написан.
Сообщение отредактировал zheka - Mar 22 2015, 07:30
|
|
|
|
|
Mar 25 2015, 18:12
|
Гуру
     
Группа: Участник
Сообщений: 2 072
Регистрация: 14-01-06
Пользователь №: 13 164

|
Хорошо, вот вопрос для тех, у кого нет дискавери, но есть хотя бы keil. Нашел интересны пример - шаг за шагом - для тупых http://e.pavlin.si/2014/07/10/stm32f4-disc...t-step-by-step/Я дошел до шага 7. Во вкладке драйверы у меня нет USB. Хотя MDK Middleware и ARM CMSIS я обновлял средствами самого keil и версию указывал ту же самую, что в статье. Пишет что не хватает компонентов. А кака их скачать, если pack скачивается целиком и в каком-то урезанном объеме.... Может кто-нибудь попробовать дойти до шага 7? Не с последними версиями библиотек, а с теми, что указаны... У меня уже 6 примеров на рабочем столе валяется и ни один по тем или иным причинам не работает. И гугл не особо помогает. Мне нужно немного - KEIL+CDC+Discovery - готовый простой пример. Нигде нет... Есть под Eclipse полно примеров, но переделка результатов не дала - Hard fault на этапе перехода из SystemInit в main() Далее - шаг 10, где предлагается настроить клок в RTE-Device.h. У меня все есть во вкладке, кровме клока. Это какое-то издевательство...
Сообщение отредактировал zheka - Mar 25 2015, 18:05
|
|
|
|
|
Mar 25 2015, 20:31
|
Гуру
     
Группа: Участник
Сообщений: 2 072
Регистрация: 14-01-06
Пользователь №: 13 164

|
Ну вот к примеру http://www.wolinlabs.com/blog/stm32f4.virtual.com.port.htmlСкажите, это вообще в keil будет работать? Цитата а переменная то не в библиотеке случаем? а не подключить ли ее в проект надо? Ну этот проект как раз собран с ошибкой - там последние версии библиотек, а они несовместимы с каким-то драйвером. Так что даже если и скомпилится, работать не будет. С правильными версиями библиотек, сделанное как в статье http://e.pavlin.si/2014/07/10/stm32f4-disc...t-step-by-step/ у меня скомпилилось, но поскольку я не нашел вкладку clock configuration, поэтому устройство не обнаруживается. Еще раз говорю, я не прошу за меня писать проекты. Просто ищу человека, который работал с CDC на Discovery с KEIL. Мне нужен пример, который без бубнов скомпилится, запустится, передаст байт туда и обратно. С остальным я разберусь сам. Пост 14. Если это перестанет вылетать на этапе перехода от SystemInit к main(), я буду несказанно рад.
|
|
|
|
|
Mar 27 2015, 04:30
|
Гуру
     
Группа: Участник
Сообщений: 2 072
Регистрация: 14-01-06
Пользователь №: 13 164

|
ОК. Тогда проблема следующая. ЗАпустил на компе программу Terminal и ловлю посылки. А посылки такие (имитирую передачу кадра 640х480) Код for (i=0;i<480;i++) { for (j=0;j<10;j++) usb_cdc_printf("....... ....... ....... ....... ....... ....... ....... ...\r\n"); usb_cdc_printf("END_LINE\r\n"); } usb_cdc_printf("END_FRAME END_FRAME END_FRAME END_FRAME END_FRAME \r\n"); Delay(50); Получаю явные пропуски данных. Как для начала понять - контроллер отправляет не все или комп захлебывается? Т
|
|
|
|
|
Apr 14 2015, 09:38
|
Гуру
     
Группа: Участник
Сообщений: 2 072
Регистрация: 14-01-06
Пользователь №: 13 164

|
Возвращаюсь к проекту. Мне удалось-таки настроить CDC на последней 5 версии KEIL и ее библиотеках. ПО упомянутой мной ранее СТАТЬЕКак выяснилось, отправка байтов все-таки не поспевала за командами контроллера. Ибо когда я поставил буфер 1024 байта, а отправляю единовременно по 640 байт, проблемы не возникает. Но, сами понимаете, решение это временное. Хотелось бы знать, как мне организовать проверку, окончено ли задание по отправке пакета, можно ли направлять следующий? Как понять, свободен ли буфер? Перековырял всю библиотеку - то ли лыжи не едут... то ли я не пойму как это сделать...
|
|
|
|
|
Apr 14 2015, 11:55
|
Гуру
     
Группа: Участник
Сообщений: 2 072
Регистрация: 14-01-06
Пользователь №: 13 164

|
Действительно, проблема оказалась временно решенной. Как только я попытался передать большой поток данных, начались тормоза. Первые ошибки отправки посыпались примерно на 16 500 байте. Вот как я отправляю Код while(1) {
if (USBD_Configured (0)) { /* USB -> MCU */ if (usb_rx_ch == -1) { usb_rx_ch = USBD_CDC_ACM_GetChar (0); } if (usb_rx_ch != -1) {
for (j=0;j<480;j++) { for (i=0;i<640;i++) { sprintf(ss,"%d ",i); RESULT=USBD_CDC_ACM_PutChar (0, ss[0]); // на эту хрень не обращайте внимания, это временно урезаный кусок. if (RESULT==-1) { if (ERRORS==0) {ierr=i;jerr=j;} ERRORS++; } } } } if (usb_rx_ch != LF) usb_rx_ch = -1; } } ierr и jerr - для контроля, когда возникает первая ошибка. Так как все-таки правильно передавать данные?
Сообщение отредактировал zheka - Apr 14 2015, 12:06
|
|
|
|
|
Apr 15 2015, 06:15
|
Гуру
     
Группа: Участник
Сообщений: 2 072
Регистрация: 14-01-06
Пользователь №: 13 164

|
Цитата Вроде б очевидно, что если функция не может отправить данные, надо чуть-чуть подождать Цитата Чёрт, ну вот как, как до этого можно догадаться?! Не надо иронизировать, а? Я прекрасно понимаю, что нужно чуть-чуть подождать, я спрашивал, как не ждать определенное время, а четко ловить момент, когда можно еще что-то пихать. Что-то типа while(cdc_is_busy) {} Цитата Как ускорять кейловскую библиотеку, я не знаю. Подозреваю, что только выкидыванием и переписыванием. Очень странное предложение. А я думал настройками, коих великое множество.
|
|
|
|
|
Apr 15 2015, 10:30
|

Профессионал
    
Группа: Свой
Сообщений: 1 032
Регистрация: 13-03-08
Из: Маськва
Пользователь №: 35 877

|
Если USBD_CDC_ACM_PutChar () не смог сделать этот самый putchar, он вернёт -1. Соответственно, ничего страшного не случится, если попросить его сделать это ещё раз. И ещё.
А настроек там немного совсем. Во всяком случае, таких, которые может крутить пользователь. Размер пакета там уже установлен в 64 байта, что ещё можно поменять, не знаю. Как оно устроено внутри, кейл не говорит.
--------------------
Тут обсуждается творческий порыв, а не соответствие каким-либо стандартам ©
|
|
|
|
|
Apr 15 2015, 10:54
|
Гуру
     
Группа: Участник
Сообщений: 2 072
Регистрация: 14-01-06
Пользователь №: 13 164

|
Про ошибки - проехали. ПРо быстродействие - я уже где-то вычитал, что для того чтобы достичь максимума в 1.2 мбайт/с, нужно оперировать нужно массивами. Для массивов есть спецфункция Код extern int32_t USBD_CDC_ACM_WriteData (int8_t instance, const uint8_t *buf, int32_t len); Как видите len - 32битный. Но в настройках больше 64 байт в endpoint не ставится. Даже если сам buf объявить больше чем на 64 байта - устройство USB не определяется. Где собака порылась?
Сообщение отредактировал zheka - Apr 15 2015, 10:56
|
|
|
|
|
Apr 15 2015, 11:09
|
Гуру
     
Группа: Участник
Сообщений: 2 072
Регистрация: 14-01-06
Пользователь №: 13 164

|
Цитата(Golikov A. @ Apr 15 2015, 13:59)  может где то в районе спецификации USB, по которой контрольная точка больше 64 байт для HS, FS устройств не допускает? Возможно, но для HS размера пакета в настройках ставится 512 байт. И тем не менее - это тоже не 32 бит, как допускает параметр len Это и наталкивало меня на мысль, что размер буфера - вещь аппаратная, в функцию можно пихать столько, сколько позволяет разерность len и ресурсы конкретного контроллера, а она уже сама позаботится о разбивке. Кроме того, в настройках есть такой параметр: Maximum Communication Device Send Buffer Size, который выставляется до 1024 байт. СОбственно у меня он и выставлен в 1024 байт и я уже раскатал на них губу.
Сообщение отредактировал zheka - Apr 15 2015, 11:27
|
|
|
|
|
Apr 15 2015, 12:32
|
Гуру
     
Группа: Участник
Сообщений: 2 072
Регистрация: 14-01-06
Пользователь №: 13 164

|
Цитата Буфер, в который пишет USBD_CDC_ACM_WriteData() (ну и ваши тысячи USBD_CDC_ACM_PutChar()) организован в основной памяти контроллера, вооооот.... Тогда почему же, если я делаю вот так Код uint8_t DataOut[64]; uint8_t *pDataOut; ..... USBD_CDC_ACM_WriteData(0,pDataOut,64); и ставлю в первой строке DataOut[640], то при запуске USB вообще не определяется? Работая кусками по 64 байта и склеивая их по 10 уже на компьютере, я все-таки получил вывод картинки со скоростью 1 кадр за 0.3 секунды (как раз примерно 900 кб/сек). Но гложет меня этот короткий буфер. Я пока-что искусственно генерю содержимое памяти. Сейчас вот прикручу DCMI и DMA - подозреваю что будут проблемы. Хотелось целую строку запихивать в буфер и тут же по сигналу окончания считывания строки отправлять ее по USB... Максимум чего удалось добиться - uint8_t DataOut[256];
Сообщение отредактировал zheka - Apr 15 2015, 11:53
|
|
|
|
|
Apr 15 2015, 12:58
|
Гуру
     
Группа: Участник
Сообщений: 2 072
Регистрация: 14-01-06
Пользователь №: 13 164

|
Цитата А то сейчас можно подумать, что DataOut[] локальная переменная, для которой просто не хватает стека. Ах тыж ёшкин кот... точно!!!Она у меня и правда локальная. Сделал глобальной, выставил 640 байт - все пашет. Спасибо! P.S. Ушел к знакомому шаману за специальным бубном, который потребуется чтобы прикрутить DCMI.....
Сообщение отредактировал zheka - Apr 15 2015, 12:59
|
|
|
|
|
Apr 18 2015, 18:59
|
Гуру
     
Группа: Участник
Сообщений: 2 072
Регистрация: 14-01-06
Пользователь №: 13 164

|
Продолжаю пляски с бубном Прикрутил камеру. НА текущий момент читатся и пишутся регистры, камера, судя по осциллограммам работает. О том, что нормально работает камера и са DCMI свидетельствует то, что помещенный в окно отладчика Watch регистр DCMI->DR мпостоянно изеняется, приченм, если камеру закрыть, там нули, а если посветить - то чем ярче, тем больше выпозают числа. А вот с DMA какие-то проблемы - выделенный по дкадр буфер все время пуст. ДЛя проверки даже предварително заполнял его заданным значениями - они отображаются, но не меняются. Вот инициализация: CODE static void Camera_HW_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; DCMI_InitTypeDef DCMI_InitStructure; DMA_InitTypeDef DMA_InitStructure; NVIC_InitTypeDef NVIC_InitStructure;
__IO uint32_t Timeout = TIMEOUT_MAX;
RCC_AHB1PeriphClockCmd(SCCB_Clock, ENABLE);
// Configure SIO_C and SIO_D as OUT (for SCCB/I2C) GPIO_InitStructure.GPIO_Pin = SIO_C_Pin | SIO_D_Pin;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; GPIO_InitStructure.GPIO_OType = GPIO_OType_OD; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; // PullUp is include on module GPIO_Init(SCCB_Port, &GPIO_InitStructure);
// Configure MCO0(PA8) as clock out for Camera Module (XCLK pin) OV7670_XCLK_Conf();
// Configures the DCMI GPIOs to interface with the OV7670 camera module // Enable DCMI GPIOs clocks RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOB | RCC_AHB1Periph_GPIOC | RCC_AHB1Periph_GPIOE, ENABLE);
// Connect DCMI pins to AF13 // PORTA GPIO_PinAFConfig(GPIOA, GPIO_PinSource4, GPIO_AF_DCMI); // HSYNC GPIO_PinAFConfig(GPIOA, GPIO_PinSource6, GPIO_AF_DCMI); // PCLK GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_DCMI); // D0 GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_DCMI); // D1
// PORTB GPIO_PinAFConfig(GPIOB, GPIO_PinSource6, GPIO_AF_DCMI); // D5 GPIO_PinAFConfig(GPIOB, GPIO_PinSource7, GPIO_AF_DCMI); // VSYNC GPIO_PinAFConfig(GPIOB, GPIO_PinSource8, GPIO_AF_DCMI); // D6 GPIO_PinAFConfig(GPIOB, GPIO_PinSource9, GPIO_AF_DCMI); // D7 -
// PORTC GPIO_PinAFConfig(GPIOC, GPIO_PinSource11, GPIO_AF_DCMI); // D4
// PORTE GPIO_PinAFConfig(GPIOE, GPIO_PinSource0, GPIO_AF_DCMI); // D2 GPIO_PinAFConfig(GPIOE, GPIO_PinSource1, GPIO_AF_DCMI); // D3
// DCMI GPIO configuration // D0..D1(PA9/10), HSYNC(PA4), PCLK(PA6) GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_6 | GPIO_Pin_9 | GPIO_Pin_10; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP ; GPIO_Init(GPIOA, &GPIO_InitStructure);
// D5..D7(PB6/8/9), VSYNC(PB7) GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_9; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP ; GPIO_Init(GPIOB, &GPIO_InitStructure);
// D4(PC11) GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP ; GPIO_Init(GPIOC, &GPIO_InitStructure);
// D2..D3(PE0/1) GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP ; GPIO_Init(GPIOE, &GPIO_InitStructure); //--------------------------------------------------------------------------------------- // GPIO_PinAFConfig(GPIOC, GPIO_PinSource6, GPIO_AF_DCMI); //d0 // GPIO_PinAFConfig(GPIOC, GPIO_PinSource7, GPIO_AF_DCMI); //d1 // GPIO_PinAFConfig(GPIOC, GPIO_PinSource8, GPIO_AF_DCMI); //d2
//--------------------------------------------------------------------------------------- // Configures the DCMI to interface with the OV7670 camera module // Enable DCMI clock RCC_AHB2PeriphClockCmd(RCC_AHB2Periph_DCMI, ENABLE);
// Reinitialize DCMI_DeInit();
// DCMI configuration DCMI_InitStructure.DCMI_CaptureMode = DCMI_CaptureMode_Continuous; DCMI_InitStructure.DCMI_SynchroMode = DCMI_SynchroMode_Hardware; DCMI_InitStructure.DCMI_PCKPolarity = DCMI_PCKPolarity_Rising; DCMI_InitStructure.DCMI_VSPolarity = DCMI_VSPolarity_High; DCMI_InitStructure.DCMI_HSPolarity = DCMI_HSPolarity_Low; DCMI_InitStructure.DCMI_CaptureRate = DCMI_CaptureRate_All_Frame; DCMI_InitStructure.DCMI_ExtendedDataMode = DCMI_ExtendedDataMode_8b;
DCMI_Init(&DCMI_InitStructure); // Configures the DMA2 to transfer Data from DCMI // Enable DMA2 clock RCC_AHB1PeriphClockCmd(DMA_Camera_STREAM_CLOCK, ENABLE);
// DMA2 Stream1 Configuration DMA_DeInit(DMA_CameraToRAM_Stream); // Check if the DMA Stream is disabled before enabling it. // Note that this step is useful when the same Stream is used multiple times: // enabled, then disabled then re-enabled... In this case, the DMA Stream disable // will be effective only at the end of the ongoing data transfer and it will // not be possible to re-configure it before making sure that the Enable bit // has been cleared by hardware. If the Stream is used only once, this step might // be bypassed. while (DMA_GetCmdStatus(DMA_CameraToRAM_Stream) != DISABLE) { } DMA_InitStructure.DMA_Channel = DMA_Camera_Channel; DMA_InitStructure.DMA_PeripheralBaseAddr = DCMI_DR_ADDRESS; DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&RAM_Buffer; //DMA_InitStructure.DMA_Memory0BaseAddr = 0x60020000;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory; DMA_InitStructure.DMA_BufferSize = BuffSize; // DMA_InitStructure.DMA_BufferSize = 1;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; // DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word; DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; DMA_InitStructure.DMA_Priority = DMA_Priority_High; DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Enable; DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full; DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single; DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
DMA_Init(DMA_CameraToRAM_Stream, &DMA_InitStructure);
// Enable DMA Stream Transfer Complete interrupt DMA_ITConfig(DMA_CameraToRAM_Stream, DMA_IT_TC , ENABLE);
// Check if the DMA Stream has been effectively enabled. // The DMA Stream Enable bit is cleared immediately by hardware if there is an // error in the configuration parameters and the transfer is no started (ie. when // wrong FIFO threshold is configured ...) Timeout = TIMEOUT_MAX; while ((DMA_GetCmdStatus(DMA_CameraToRAM_Stream) != ENABLE) && (Timeout-- > 0)) { }
// Check if a timeout condition occurred if (Timeout == 0) { // Manage the error: to simplify the code enter an infinite loop while (1) { // Dopísa program } } // // Enable the DMA Stream IRQ Channel NVIC_InitStructure.NVIC_IRQChannel = DMA_Camera_STREAM_IRQ; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure);
}
Буфер объявлен так Код __IO uint16_t RAM_Buffer[BuffSize]; Ну и вот что у меня в прерываниях Код void DMA_Camera_STREAM_IRQHANDLER(void) { uint16_t i; // Test on DMA Stream Transfer Complete interrupt if(DMA_GetITStatus(DMA_CameraToRAM_Stream, DMA_Camera_IT_TCIF)) { // LCD_REG = 0x0022; //for(i = 0; i < BuffSize; i++) // LCD_RAM = RAM_Buffer[i];
// Clear DMA Stream Transfer Complete interrupt pending bit DMA_ClearITPendingBit(DMA_CameraToRAM_Stream, DMA_Camera_IT_TCIF); } }
void DCMI_IRQHandler(void) { uint16_t i;
if(DCMI_GetITStatus(DCMI_IT_FRAME)) { // LCD_REG = 0x0022; //for(i = 0; i < BuffSize; i++) // LCD_RAM = RAM_Buffer[i]; //for(i = 0; i < 28800; i++) // LCD_RAM = 0x0000; DCMI_ClearITPendingBit(DCMI_IT_FRAME); } } Оба прерывания вызываются, все ОК, Но буфер пуст... У меня вопрос - а нужен ли мне собственно DMA? МОжно ли как-то без него заполнять буфер длиной 640 байт а по прерыванию новой строки отправлять этот буфер по USB? ДОБАВЛЮ: Если это Код // DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable; заменить на это Код DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; // DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable; ну то есть включить DMA_MemoryInc, то в буфере оказываются данные, но в дальнейшем не изменяются. И прерывание DMA_Stream не вызывается...
Сообщение отредактировал zheka - Apr 18 2015, 18:57
|
|
|
|
|
Apr 19 2015, 11:08
|
Гуру
     
Группа: Участник
Сообщений: 2 072
Регистрация: 14-01-06
Пользователь №: 13 164

|
Таак... У меня каша в голове пока что.... Вот смотрите, мне нужно следующее - чтобы DMA заполнял данными из DCMI буфер длиной в одну строку (1280 байт при RGB565), чтобы первый байт строки был первым байтом буфера. Далее - по окончанию передачи строки (не знаю, как лучше ее ловить, по прерываниям из DCMI или в DMA есть какое прерывание, означающее что вся строка передана, в этот момент я собираюсь забирать из буфера данные и отправлять их по USB (это уже настроено). Вот мои последние настройки DMA и DCMI CODE DCMI_InitStructure.DCMI_CaptureMode = DCMI_CaptureMode_Continuous; DCMI_InitStructure.DCMI_SynchroMode = DCMI_SynchroMode_Hardware; DCMI_InitStructure.DCMI_PCKPolarity = DCMI_PCKPolarity_Rising; DCMI_InitStructure.DCMI_VSPolarity = DCMI_VSPolarity_High; DCMI_InitStructure.DCMI_HSPolarity = DCMI_HSPolarity_Low; DCMI_InitStructure.DCMI_CaptureRate = DCMI_CaptureRate_All_Frame; DCMI_InitStructure.DCMI_ExtendedDataMode = DCMI_ExtendedDataMode_8b;
DCMI_Init(&DCMI_InitStructure); // Configures the DMA2 to transfer Data from DCMI // Enable DMA2 clock RCC_AHB1PeriphClockCmd(DMA_Camera_STREAM_CLOCK, ENABLE);
// DMA2 Stream1 Configuration DMA_DeInit(DMA_CameraToRAM_Stream); // Check if the DMA Stream is disabled before enabling it. // Note that this step is useful when the same Stream is used multiple times: // enabled, then disabled then re-enabled... In this case, the DMA Stream disable // will be effective only at the end of the ongoing data transfer and it will // not be possible to re-configure it before making sure that the Enable bit // has been cleared by hardware. If the Stream is used only once, this step might // be bypassed. while (DMA_GetCmdStatus(DMA_CameraToRAM_Stream) != DISABLE) { } DMA_InitStructure.DMA_Channel = DMA_Camera_Channel; DMA_InitStructure.DMA_PeripheralBaseAddr = DCMI_DR_ADDRESS; DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&RAM_Buffer; //DMA_InitStructure.DMA_Memory0BaseAddr = 0x60020000;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory; DMA_InitStructure.DMA_BufferSize = BuffSize; // DMA_InitStructure.DMA_BufferSize = 1;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; // DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word; DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; DMA_InitStructure.DMA_Priority = DMA_Priority_High; DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Enable; DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full; DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single; DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
DMA_Init(DMA_CameraToRAM_Stream, &DMA_InitStructure);
// Enable DMA Stream Transfer Complete interrupt DMA_ITConfig(DMA_CameraToRAM_Stream, DMA_IT_TC , ENABLE);
// Check if the DMA Stream has been effectively enabled. // The DMA Stream Enable bit is cleared immediately by hardware if there is an // error in the configuration parameters and the transfer is no started (ie. when // wrong FIFO threshold is configured ...) Timeout = TIMEOUT_MAX; while ((DMA_GetCmdStatus(DMA_CameraToRAM_Stream) != ENABLE) && (Timeout-- > 0)) { }
// Check if a timeout condition occurred if (Timeout == 0) { // Manage the error: to simplify the code enter an infinite loop while (1) { // Dopísa program } } // // Enable the DMA Stream IRQ Channel NVIC_InitStructure.NVIC_IRQChannel = DMA_Camera_STREAM_IRQ; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure);
Что нужно поменять? Особенно волнует, как настраивать вот эти строки DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; // DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable; И почему в источнике слово, а в конечной точке - полслова? DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word; DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
|
|
|
|
|
Apr 22 2015, 15:56
|
Гуру
     
Группа: Участник
Сообщений: 2 072
Регистрация: 14-01-06
Пользователь №: 13 164

|
Вот черт же, где правда? Стр.41 даташита https://www.fer.unizg.hr/_download/repository/OV7670new.pdfVertical Frame (Row) Start VSTRT [7:0], VREF[2:0]То есть старшие 8 бит - в регистре VSTRT, младшие 3 бита - в регистре VREF Дальше лезем в описание регистра VREF: bit [3:2] - VREF end low 2 bits Где правда?
|
|
|
|
|
Apr 22 2015, 17:17
|
Гуру
     
Группа: Участник
Сообщений: 2 072
Регистрация: 14-01-06
Пользователь №: 13 164

|
Оказывается есть аппаратная функция захвата ОБЛАСТИ в контроллере DCMI Код typedef struct { uint16_t DCMI_VerticalStartLine; /*!< Specifies the Vertical start line count from which the image capture will start. This parameter can be a value between 0x00 and 0x1FFF */
uint16_t DCMI_HorizontalOffsetCount; /*!< Specifies the number of pixel clocks to count before starting a capture. This parameter can be a value between 0x00 and 0x3FFF */
uint16_t DCMI_VerticalLineCount; /*!< Specifies the number of lines to be captured from the starting point. This parameter can be a value between 0x00 and 0x3FFF */
uint16_t DCMI_CaptureCount; /*!< Specifies the number of pixel clocks to be captured from the starting point on the same line. This parameter can be a value between 0x00 and 0x3FFF */ } DCMI_CROPInitTypeDef; и позволяет вводить "человеческие" значения. Таким образом, у меня один вопрос к специалистам - те значения, что в камере по умолчанию - они все-таки какие координаты окна и разрешение дают? Надеюсь 0,0,640,480?
Сообщение отредактировал zheka - Apr 22 2015, 18:08
|
|
|
|
|
Apr 22 2015, 19:21
|
Гуру
     
Группа: Участник
Сообщений: 2 072
Регистрация: 14-01-06
Пользователь №: 13 164

|
Какой-то шайтан... Как не настраиваю, DCMI все равно выдает 480 строк: Код DCMI_DeInit();
// DCMI configuration DCMI_InitStructure.DCMI_CaptureMode = DCMI_CaptureMode_Continuous; DCMI_InitStructure.DCMI_SynchroMode = DCMI_SynchroMode_Hardware; DCMI_InitStructure.DCMI_PCKPolarity = DCMI_PCKPolarity_Rising; DCMI_InitStructure.DCMI_VSPolarity = DCMI_VSPolarity_High; DCMI_InitStructure.DCMI_HSPolarity = DCMI_HSPolarity_Low; DCMI_InitStructure.DCMI_CaptureRate = DCMI_CaptureRate_All_Frame; DCMI_InitStructure.DCMI_ExtendedDataMode = DCMI_ExtendedDataMode_8b;
DCMI_Init(&DCMI_InitStructure);
DCMI_CROPInitStructure.DCMI_HorizontalOffsetCount=0; DCMI_CROPInitStructure.DCMI_CaptureCount=320*2; DCMI_CROPInitStructure.DCMI_VerticalStartLine=0; DCMI_CROPInitStructure.DCMI_VerticalLineCount=240; DCMI_CROPConfig(&DCMI_CROPInitStructure); DCMI_CROPCmd(ENABLE); DCMI_ITConfig(DCMI_IT_VSYNC, ENABLE); DCMI_ITConfig(DCMI_IT_LINE, ENABLE); DCMI_ITConfig(DCMI_IT_FRAME, ENABLE); DCMI_ITConfig(DCMI_IT_OVF, ENABLE); DCMI_ITConfig(DCMI_IT_ERR, ENABLE); А вот обработчик прерываний Код void DCMI_IRQHandler(void) { uint16_t i;
if(DCMI_GetITStatus(DCMI_IT_FRAME)) { DCMI_ClearITPendingBit(DCMI_IT_FRAME); lines=current_line; current_line=0;
}
if(DCMI_GetITStatus(DCMI_IT_VSYNC)) { DCMI_ClearITPendingBit(DCMI_IT_VSYNC); } if(DCMI_GetITStatus(DCMI_IT_ERR)) { DCMI_ClearITPendingBit(DCMI_IT_ERR); }
if(DCMI_GetITStatus(DCMI_IT_LINE)) { current_line++; DCMI_ClearITPendingBit(DCMI_IT_LINE); } } В дебаггере у меня lines. Как только ловится кадр, в Lines помещается значение насчитанных строк.
|
|
|
|
|
Apr 26 2015, 09:02
|
Гуру
     
Группа: Участник
Сообщений: 2 072
Регистрация: 14-01-06
Пользователь №: 13 164

|
Камера поддается, но не сдается. Куски картинки в искаженном цвете я уже вижу. Но как-то неправильно DCMI и DMA у меня кооперируются. Интерфейс DCMI имеет регистр DCMI->DR, содержащий 32 бита, то есть в режиме RGB565 в него кладется 4 байта - информация о 2-х пикселях. Я настроил камеры на выдачу фрагмента размерами 200х200 пикселей, то есть размер буфера у меня 80 000 байт, длина строки 400 байт. Я заполняю буфер через DMA, а потом пакетами по 400 байт пересылаю картинку на компьютер. В итоге картинка получается странная - складывается ощущение, что строка все же имеет длину 200 байт и запись в картинку получается следующего формата 1 строка 2 строка 3 строка 4 строка 5 строка 6 строка Плюс почему-то нижняя часть картинки оказывается вверху и наоборот. А верхняя половина буфера пуста. Собственно с передаче картинки на комп и ее расшифровкой проблем нет - заполнял буфер искусственно, получал правильную картинку. ПРоблемы с записью в DMA. Вот код CODE extern __IO uint8_t RAM_Buffer[80000]; uint8_t *pRAM_Buffer;
..................................................
DCMI_InitStructure.DCMI_CaptureMode = DCMI_CaptureMode_Continuous; DCMI_InitStructure.DCMI_SynchroMode = DCMI_SynchroMode_Hardware; DCMI_InitStructure.DCMI_PCKPolarity = DCMI_PCKPolarity_Rising; DCMI_InitStructure.DCMI_VSPolarity = DCMI_VSPolarity_High; DCMI_InitStructure.DCMI_HSPolarity = DCMI_HSPolarity_Low; DCMI_InitStructure.DCMI_CaptureRate = DCMI_CaptureRate_All_Frame; DCMI_InitStructure.DCMI_ExtendedDataMode = DCMI_ExtendedDataMode_8b;
DCMI_Init(&DCMI_InitStructure);
DCMI_ITConfig(DCMI_IT_VSYNC, ENABLE); DCMI_ITConfig(DCMI_IT_LINE, ENABLE); DCMI_ITConfig(DCMI_IT_FRAME, ENABLE);
DCMI_ITConfig(DCMI_IT_ERR, ENABLE); // Enable DCMI Capture mode
// Configures the DMA2 to transfer Data from DCMI // Enable DMA2 clock RCC_AHB1PeriphClockCmd(DMA_Camera_STREAM_CLOCK, ENABLE);
// DMA2 Stream1 Configuration DMA_DeInit(DMA_CameraToRAM_Stream);
while (DMA_GetCmdStatus(DMA_CameraToRAM_Stream) != DISABLE) { } DMA_InitStructure.DMA_Channel = DMA_Camera_Channel; DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(&DCMI->DR); DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&RAM_Buffer;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory; DMA_InitStructure.DMA_BufferSize = BuffSize;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word; DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word; DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; DMA_InitStructure.DMA_Priority = DMA_Priority_High; DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Enable; DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full; DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single; DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
DMA_Init(DMA_CameraToRAM_Stream, &DMA_InitStructure);
// Enable DMA Stream Transfer Complete interrupt DMA_ITConfig(DMA_CameraToRAM_Stream, DMA_IT_TC, ENABLE); .......................... // Передача двухсот строк
pRAM_Buffer=RAM_Buffer; for (j=0;j<200;j++) { USBD_CDC_ACM_WriteData(0,pRAM_Buffer+400*j,400); delay_us(1000);
} Картинку прикладываю. Камера лежит на столе и в ее объектив попадает мое ухо)) Вот картинка
Сообщение отредактировал IgorKossak - Apr 26 2015, 10:24
Причина редактирования: [codebox] для длинного кода, [code] - для короткого!!!
Эскизы прикрепленных изображений
|
|
|
|
|
Apr 27 2015, 18:28
|
Гуру
     
Группа: Свой
Сообщений: 2 724
Регистрация: 14-05-07
Из: Ярославль, Россия
Пользователь №: 27 702

|
Цитата(zheka @ Apr 27 2015, 20:19)  не настроена гамма Я долго страдал от зеленых лиц... CODE sccb_wr_reg(REG_COM7, 0x80); /* reset to default values */ //sccb_wr_reg(REG_CLKRC, 0x80); sccb_wr_reg(REG_COM11, 0x0A); sccb_wr_reg(REG_COM7, 0x04); /* output format: rgb */ sccb_wr_reg(REG_RGB444, 0x00); /* disable RGB444 */ sccb_wr_reg(REG_COM15, 0xD0); /* set RGB565 */ //sccb_wr_reg(0x0C, 0x00);
// COLOR SETTING sccb_wr_reg(0x4f, 0x80); sccb_wr_reg(0x50, 0x80); sccb_wr_reg(0x51, 0x00); sccb_wr_reg(0x52, 0x22); sccb_wr_reg(0x53, 0x5e); sccb_wr_reg(0x54, 0x80); sccb_wr_reg(0x56, 0x40); sccb_wr_reg(0x58, 0x9e); sccb_wr_reg(0x59, 0x88); sccb_wr_reg(0x5a, 0x88); sccb_wr_reg(0x5b, 0x44); sccb_wr_reg(0x5c, 0x67); sccb_wr_reg(0x5d, 0x49); sccb_wr_reg(0x5e, 0x0e); sccb_wr_reg(0x69, 0x00); sccb_wr_reg(0x6a, 0x40); sccb_wr_reg(0x6b, 0x0a); sccb_wr_reg(0x6c, 0x0a); sccb_wr_reg(0x6d, 0x55); sccb_wr_reg(0x6e, 0x11); sccb_wr_reg(0x6f, 0x9f);
sccb_wr_reg(0xb0, 0x84); sccb_wr_reg(0x11, 0x81); Надеюсь этот код добавит вам счастья.
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|