Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: STM32F4, DCMI и USB
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
Страницы: 1, 2
zheka
Коллеги, хочу передавать изображения с камеры 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?

В общем, подскажите, что мне нужно для решения задачи?
Dr.Alex
Цитата(zheka @ Mar 20 2015, 09:46) *
В общем, подскажите, что мне нужно для решения задачи?

Проще всего переделать CDC на BULK.
adnega
Цитата(Dr.Alex @ Mar 20 2015, 11:20) *
Проще всего переделать CDC на BULK.

Максимум 980кБайт/сек на USB-FS.
Dr.Alex
Цитата(adnega @ Mar 20 2015, 12:29) *
Максимум 980кБайт/сек на USB-FS.

Зачем ФС? ХС надо. О скорости я недавно отчитывался.
zheka
Цитата(Dr.Alex @ Mar 20 2015, 12:37) *
Зачем ФС? ХС надо. О скорости я недавно отчитывался.


можно ссылку на отчет?
Dr.Alex
Цитата(zheka @ Mar 20 2015, 13:40) *
можно ссылку на отчет?

http://electronix.ru/forum/index.php?showtopic=126651
Golikov A.
Цитата
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 там скорости повыше
mantech
Цитата(Golikov A. @ Mar 20 2015, 13:48) *
А для решения задачи вам надо еще драйвер на стороне Windows, есть встроенный HID и практически встроенный CDC. Остальные драйверы надо писать самому, и потому обмен через другие интерфейсы вам создаст дополнительных проблем.


Так-то есть еще usb video class, по которому работают камеры в винде, он стандартный, но на стороне мк реализовать сложнее.
Golikov A.
Цитата
Так-то есть еще usb video class,

это видать что-то новое появилось... правда я так давно этим USB последний раз занимался, что оно может быть вполне и староеsm.gif
zheka
Установил я virtual comport driver версия 1.4, скачал с самого сайта ST.
Все установилось без проблем.
Но появляющийся com-порт со значком ошибки - для устройства не установлены драйверы. Хотя номер порту присваивается.
При попытке вручную что-то сделать выдается сообщение "Неправильная секция установки службы в этом ini файле"

Прошивку качал отсюда http://ctrl-v.biz/blog/7

Что я делаю не так? Ini файл прикладываю
zheka
Много бубнов разбил, но установил все-таки этот драйвер.
Объясните мне феномен - как ни переключаю скорость COM-порта в Terminal - данные идут правильные и на высокой скорости. Это как?
Andy Mozzhevilov
Цитата(zheka @ Mar 21 2015, 15:15) *
Объясните мне феномен - как ни переключаю скорость COM-порта в Terminal - данные идут правильные и на высокой скорости. Это как?

Так и есть. В USB данные будут ходить с той скоростью, сколько USB позволит.
То, что вы устанавливаете, это фактически настройки для реального COM порта, который может торчать с другой стороны USB. Они уходят отдельными командами и могут быть использованы, если нужно. Например можно сделать конвертер USB-COM и по переданным параметрам устанавливать нужную скорость UART.
zheka
А из DMA тогда как в USB писать?
Что записывать в DMA_InitStructure.DMA_Memory0BaseAddr ???
zheka
ох... у меня голова уже опухла..
Вот здесь в конце есть ссылка на якобы рабочий проект для Eclipse. http://ctrl-v.biz/blog/7
Пытаюсь переделать под Keil. Все добавил, все прописал, все пути к include тоже вбил. Не компилится и все тут.
Если кому не трудно, гляньте в аттаче...
zheka
Нашел что надо прописать.
Компилится, линкуется. Но вываливается в Hard Fault..
Ставлю брейкпоинт на самую первую строку - брейкпоинт не срабатывает.
В чем моежт быть дело?
Файл, выложенный выше, обновил.
/////////////////

Прошелся отладчиком пошагово :
Код
        IMPORT  __main

                 LDR     R0, =SystemInit
                 BLX     R0
                 LDR     R0, =__main
                 BX      R0
                 ENDP


доходит до BX R0 и вылетает в hard_fault
Стартап я правда взял от примеров от ST для дискавери4, потому как в примере для Eclipse он как будто на другом языке написан.
zheka
Пробовал запустить пример кейловский Virtual ComPort, который правда под 407IG, запускается, но устройство обнаруживается компом, но не опознается.
А в аттаче то, что я собрал с нуля новым модным визардом в Keil 5 версии. Не видит при линковке одну переменную, хотя все везде прописано.

Коллеги, ну помогите мне запустить хоть один из 3 указанных проектов.
zheka
Господа, эта задача (настройка CDC на Discovery) нерешаема? Или моя просьба слишком нагла и я прошу о слишком трудоемокой помощи?
Golikov A.
Просто сказать нечего...

А что если через куб сгенерить все и запустить? для вашей дискавери? Почему у вас все время все откуда то со стороны?

Ваш же вопрос общий, то есть надо взять дискавери и самому запустить чтобы понять что не срастается...
zheka
Хорошо, вот вопрос для тех, у кого нет дискавери, но есть хотя бы 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. У меня все есть во вкладке, кровме клока. Это какое-то издевательство...
Golikov A.
Cube же делает проект с USB CDC и вроде даже выкидывает исходники драйверов для кейла, так что не выходит?

а по кейлу, тут же вопросы лицензии, у меня в том кейле что есть вообще не активна Run-time Env, почему не знаю, может чего то не стоит, паков каких или еще что....
zheka
Слазил я в CUbeMX. Он генерирует только настройки. Кода общения (прием, передача) я не увидел.
Golikov A.
ну функции то он дает.
и прерывание настраивает.
вы галочку поставили чтобы он вам CDC USB сделал?
отмечаете что хотите USB device, а вверху в системах ставите USB CDC
zheka
ставил я все галочки. там main пустой. И файла проекта нет - пишет что проблемы. МОжет быть потому, что он заточен под 4.7, а у меня пятая версия.
Не хочу я сносить и ставить 4 версию ради Cube, неправильно это.

ДА и, если честно - я хочу попроще. МНе USB нужен а этот wizard, что в статье делает с использованием RTOS. Ну куда пушка по воробьям? Но попытки переделать кучу простых примеров под другие среды успеха не приносят.
Я выложил выше пару проектов, с которыми какая-то мелкая проблема. Они, работающие меня бы устроили.
Golikov A.
увы с 5 кейлом не помогу...

Цитата
Не видит при линковке одну переменную, хотя все везде прописано.

а переменная то не в библиотеке случаем? а не подключить ли ее в проект надо?
zheka
Ну вот к примеру
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(), я буду несказанно рад.
zheka
Заработало....
zheka
А как настраивается скорость CDC?
У меня в проекте где-то настройки USART, я с ними сначала колдовал. Потом, терзаемый смутными сомнениями, вообще закомментировал инициализацию USART - работать не перестало... Значит настройка USART ни при чем.
В функции USB_OTG_BSP_Init ничего такого про скорость нет..
Golikov A.
скорость никак не настраивается.... Она не имеет смысла, будет работать на любой до максимальной
CDC же передает данные по USB, а оно имеет свою скорость, и ограничивает вас только максимумом и все...

настройки скорости в винде в виртуальном порте - это так, атавизм. Иногда их можно использовать на стороне приемника, чтобы если данные дальше по UART пойдут, задать скорость по выставленной, но если просто данные гонять надо, то скорость не имеет смысла
zheka
ОК.
Тогда проблема следующая. ЗАпустил на компе программу 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);


Получаю явные пропуски данных.
Как для начала понять - контроллер отправляет не все или комп захлебывается?
Т
Golikov A.
комп вряд ли.
Надо смотреть что за коды ошибки возвращают функции отправки... Только предварительно надо по ним пройтись и посмотреть, там часто бывает ошибочные ситуации просто заглушены кодом что все хорошо. Так что раскрутите все функции до самого копирования в буфер отправки, проверьте возвраты ошибок, и поглядите где флаг USB сбрасываются. По идее ситуация что хочется, а не можется должна быть обозначена.

А со стороны компа буферы гиганские, его трудно перегрузить ИМХО...
zheka
Да как же это проверить, если функция всегда будет возвращать USB_OK?
Код
static uint16_t cdc_DataTx (uint8_t* Buf, uint32_t Len)
{

    uint32_t i;
    //loop through buffer
    for( i = 0; i < Len; i++ )
    {
        //push data into transfer buffer
        APP_Rx_Buffer[APP_Rx_ptr_in] = Buf[i];
        //increase pointer value
        APP_Rx_ptr_in++;
        /* To avoid buffer overflow */
        if(APP_Rx_ptr_in == APP_RX_DATA_SIZE)
        {
            APP_Rx_ptr_in = 0;
        }
    }

    return USBD_OK;
}

Смотрел разные библиотеки, "говор" в них немного разный, но суть этой функции везде одна и та же
Golikov A.
эта хрень не уменьшается по мере отправки?
APP_Rx_ptr_in ?

Если нет, то значит должен быть еще указатель который показывает где сейчас указатель последних отправленных данных

zheka
Возвращаюсь к проекту.
Мне удалось-таки настроить CDC на последней 5 версии KEIL и ее библиотеках. ПО упомянутой мной ранее СТАТЬЕ
Как выяснилось, отправка байтов все-таки не поспевала за командами контроллера. Ибо когда я поставил буфер 1024 байта, а отправляю единовременно по 640 байт, проблемы не возникает.
Но, сами понимаете, решение это временное. Хотелось бы знать, как мне организовать проверку, окончено ли задание по отправке пакета, можно ли направлять следующий? Как понять, свободен ли буфер? Перековырял всю библиотеку - то ли лыжи не едут... то ли я не пойму как это сделать...
zheka
Действительно, проблема оказалась временно решенной.
Как только я попытался передать большой поток данных, начались тормоза. Первые ошибки отправки посыпались примерно на 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 - для контроля, когда возникает первая ошибка.

Так как все-таки правильно передавать данные?
esaulenka
Вроде б очевидно, что если функция не может отправить данные, надо чуть-чуть подождать, и это не ошибка, а вполне стандартная ситуация.

PS всегда считал, что документацию кейл содержит в порядке. Ан нет - в код повсюду добавили параметр instance, а в описании на сайте его нет.
zheka
Спасибо, я уже в принципе и сам дошел до этого, ставлю небольшую задержку между отправками каждого байта. Подобрал ее опытным путем, пытаясь получить максимальную скорость. В итоге - 307200 байт передаются примерно за секунду.
Кто-то писал, что CDC позволяет выжать 900 кбайт/сек.
Как этого добиться?
esaulenka
Чёрт, ну вот как, как до этого можно догадаться?!
Есть обратная связь, получилось положить в буфер CDC или не получилось. Почему бы ей не пользоваться?

Как ускорять кейловскую библиотеку, я не знаю. Подозреваю, что только выкидыванием и переписыванием.
zheka
Цитата
Вроде б очевидно, что если функция не может отправить данные, надо чуть-чуть подождать

Цитата
Чёрт, ну вот как, как до этого можно догадаться?!

Не надо иронизировать, а?
Я прекрасно понимаю, что нужно чуть-чуть подождать, я спрашивал, как не ждать определенное время, а четко ловить момент, когда можно еще что-то пихать. Что-то типа while(cdc_is_busy) {}

Цитата
Как ускорять кейловскую библиотеку, я не знаю. Подозреваю, что только выкидыванием и переписыванием.

Очень странное предложение. А я думал настройками, коих великое множество.
esaulenka
Если USBD_CDC_ACM_PutChar () не смог сделать этот самый putchar, он вернёт -1.
Соответственно, ничего страшного не случится, если попросить его сделать это ещё раз. И ещё.

А настроек там немного совсем. Во всяком случае, таких, которые может крутить пользователь. Размер пакета там уже установлен в 64 байта, что ещё можно поменять, не знаю.
Как оно устроено внутри, кейл не говорит.
zheka
Про ошибки - проехали.
ПРо быстродействие - я уже где-то вычитал, что для того чтобы достичь максимума в 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 не определяется.

Где собака порылась?


Golikov A.
может где то в районе спецификации USB, по которой контрольная точка больше 64 байт для HS, FS устройств не допускает?
zheka
Цитата(Golikov A. @ Apr 15 2015, 13:59) *
может где то в районе спецификации USB, по которой контрольная точка больше 64 байт для HS, FS устройств не допускает?

Возможно, но для HS размера пакета в настройках ставится 512 байт. И тем не менее - это тоже не 32 бит, как допускает параметр len
Это и наталкивало меня на мысль, что размер буфера - вещь аппаратная, в функцию можно пихать столько, сколько позволяет разерность len и ресурсы конкретного контроллера, а она уже сама позаботится о разбивке.

Кроме того, в настройках есть такой параметр: Maximum Communication Device Send Buffer Size, который выставляется до 1024 байт. СОбственно у меня он и выставлен в 1024 байт и я уже раскатал на них губу.
esaulenka
цитаты из исходников кейла:

* - 'Maximum Communication Device Send Buffer Size' specifies the maximum
* value for \em len in \ref USBD_CDC_ACM_WriteData

// <o>Maximum Communication Device Send Buffer Size
// <i>Specifies size of buffer used for sending of data to USB Host.
// <8=> 8 Bytes <16=> 16 Bytes <32=> 32 Bytes <64=> 64 Bytes
// <128=>128 Bytes <256=>256 Bytes <512=>512 Bytes <1024=>1024 Bytes
#define USBD_CDC%Instance%_SEND_BUF_SIZE 1024


Буфер, в который пишет USBD_CDC_ACM_WriteData() (ну и ваши тысячи USBD_CDC_ACM_PutChar()) организован в основной памяти контроллера, и оттуда библиотека перекладывает в контроллер USB кусочками по 64 байта.
zheka
Цитата
Буфер, в который пишет 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];
aaarrr
Цитата(zheka @ Apr 15 2015, 15:32) *
Максимум чего удалось добиться - uint8_t DataOut[256];

Вы бы пояснили, в ситуации, когда USB не определяется, 640 и 256 фигурируют только в размерности DataOut[], или при вызове USBD_CDC_ACM_WriteData() тоже?

А то сейчас можно подумать, что DataOut[] локальная переменная, для которой просто не хватает стека.
zheka
Цитата
А то сейчас можно подумать, что DataOut[] локальная переменная, для которой просто не хватает стека.


Ах тыж ёшкин кот... точно!!!
Она у меня и правда локальная. Сделал глобальной, выставил 640 байт - все пашет.
Спасибо!

P.S. Ушел к знакомому шаману за специальным бубном, который потребуется чтобы прикрутить DCMI.....
zheka
Продолжаю пляски с бубном
Прикрутил камеру. НА текущий момент читатся и пишутся регистры, камера, судя по осциллограммам работает.
О том, что нормально работает камера и са 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
Таак... У меня каша в голове пока что....
Вот смотрите, мне нужно следующее - чтобы 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;
Golikov A.
В ДМА настраиваю ширину входного и выходного канала
оно может 32 битные числа по 8 бит в UART перекладывать или собирать 16 битный SPI d 32 битные int.
Также в ДМА настраивают писать в один адрес или автоматически сдвигать. Если вы кладете данные в UART, например, то адрес приемника один, и ДМА делают без автоинкремента. А если вы кладете данные в память, то надо чтобы каждые новые данные клались в новый адрес, и тогда нужен автоинкремент.

Теперь смотрите ширину входных - выходных ваших данных и постоянство адресов и настраивайте ДМА.
zheka
Вы мне объясните еще две вещи - как в DCMI настроить частоту PIX_CLK и почему D0-D7 настраиваются как выходы? Ведь в камеру если что и пишется, то по i2c, но никак не по шине данных..
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.