OV7670, Generic STM32F103RC и ILI9341 Дисплей

Rogerclark
Пн 27 апреля 2015 12:33
Ребята,

Просто чтобы взять мяч..

Один проект, над которым я работал, - это попытка получить камеру OV7670, работающую с платой STM32

У меня была доска с камеры OV7670 в течение по крайней мере года, но я обнаружил, что она почти непригодна для Uno или Mega Arduino, потому что скорость процессора (16 МГц) слишком низкая на этих платах AVR, и им не хватает достаточно ОЗУ, чтобы сохранить полезное изображение

Другая проблема с использованием AVR Arduino с этими модулями камеры заключается в том, что модуль без FIFO требуется внешние часы не менее 10 МГц (я думаю, что некоторым людям удается заставить их работать при 8 МГц, но я думаю, что это ниже, чем у спецификация позволяет)

Я знаю, что можно заставить AVR вывести часы, но один метод требует, чтобы в чипе были взорваны специальные предохранители, поэтому трудно просто использовать Arduino IDE, чтобы сделать это

Доски STM32 выглядят гораздо лучшим вариантом для подключения к камере, потому что более крупные процессоры имеют до 64 тыс. Отурми, что является много для хранения разумной рамы разрешения, они также могут генерировать 10 МГц (или более высокие часы), просто используя PWM, и и. Конечно, скорость процессора 72 МГц на всех STM32F103 также позволяет им легче читать и обрабатывать данные изображения, что возможно на плате AVR 16 МГц.


В любом случае, так много для теории.

До сих пор мне удалось генерировать часы, а также общаться с камерой через его шину SCCB (вывод I2C), однако мне меньше повезло, читая изображение.

Я опубликую код и обновление об этом, когда у меня будет больше времени.

Аасакти
Втюж 07 июля 2015 г., 6:19
Привет, Роджер, я провожу подобный проект, как ваш, но я не знаю, с чего начать. Я хочу взять один рамный формат RGB от OV7670 с мини -клоном кленового кленового клона от Baite и напрямую отправлять все данные на компьютер через сериал. Я использую код с форума Arduino, я попытался получить ответ от i2c, но ничего не произойдет. У вас есть несколько советов для меня? Или вы знаете другую камеру с необработанным форматом вывода RGB?

Rogerclark
Втюж 07 июля 2015 г. 6:23 утра
У меня есть код, я постараюсь его найти.

OV7670 I2C не является стандартным, он не будет работать со скоростью I2C, которую использует STM32 (250 кбит / с)

Так что мне пришлось замедлить его.

Я нашел код, с которым я связывался, и он общается через Wire aka SCCB с камерой, но я понятия не имею, какую настройку отправляется на камеру, так как я только что взял пример кода, а камера сотни сотни регистров, которые необходимо правильно настроить, чтобы он работал хорошо.

Кроме того.

В коде, который я разместил, он даже не захватывает пиксель, если вы видите в строке 392, он просто увеличивает счетчик пикселей, но именно здесь вам нужно поместить код, чтобы прочитать пиксель.

я.E Я никогда не получаю последовательное количество пикселей.

Я думаю, что Mrarduino делает это не для того, чтобы проверять href, все, что он делает, это ждет Vsync, а затем подсчитывает количество поднимающихся краев на пиксельных часах (как просто ищет подъем и увеличение или уменьшение счетчика, даже на 16 МГц avr доска.

Действительно то, что нам нужно сделать, это использовать ввод таймера и DMA, чтобы получить данные каждые восходящие края пиксельных часов, но у меня не было времени, чтобы выяснить, как настроить как канал таймера, так и канал DMA, чтобы сделать этот.

Я знаю, что Victor_pv занят другими вещами, связанными с DMA и Timer, но когда он закончил с этим, у него может быть некоторые идеи о том, как настроить код, чтобы сделать захват пикселей в DMA,

КСТАТИ. Чтобы эффективно захватить пиксели, вам нужны все 8 бит пикселя на том же порту E.глин. PA или PB или ПК и т. Д
Таким образом, я закончил тем, что использовал плату STM32F103RCT, так как в одном из портов есть 8 GPIO

В любом случае,

По крайней мере, вы сможете общаться через SCCB с вашей камерой

Пса. Он не будет общаться через SCCB, если вы не предоставите его часами 10 МГц

Мой код выводит часы, но я не смотрел его в течение нескольких месяцев, поэтому я не могу вспомнить, на какой PIN он на.

Так что вам нужно прочитать код, чтобы решить его

Стивестронг
Ср. 04 ноября 2015 г., 13:42
Привет, Роджер,
Это было бы одним из моих будущих проектов. У меня был один Pro Mini, работающий с камерой (без FIFO), я действительно мог прочитать пиксели, показывающие реальную картинку!
В этой настройке я только что натолкнул данные Pixel через UART->Wi -Fi Bridge к сценарию PHP (сервер Apache), который обрабатывал дальнейшее изображение.
К сожалению, ссылка на данные не всегда была надежной, а скорость ужасно медленная.
На этот раз я постараюсь прочитать только подмножество всего изображения, чтобы оно подходило в ОЗУ. В качестве альтернативы я мог бы также использовать свой внешний 64 -мегабитный SRAM по SPI, чтобы временно хранить данные изображения.
Кстати, есть ли какой -либо внешний SRAM LIB, доступный для STM32? Может даже с передачей DMA?
Я проверю вас код и дам вам знать, если я смогу получить некоторые полезные результаты.
Ваше здоровье,
Стив

Стивестронг
Солнце 13 марта 2016 г., 17:43
Всем привет,
Мне наконец -то удалось получить изображение от чипа камеры OV7670.
Я использовал SW от Roger в качестве отправной точки. Тем не менее, настройки камеры не подойдут правильно.
У меня был еще один проект, основанный на Atmega328p Pro Mini, который работал, и я импортировал эти настройки.
А также переработал часть I2C, которая не сработала в начале (я не знаю точно, почему...).
Мои требования были:
- Используйте только серой масштаб 8 бит
- Используйте наименьшее разрешение, чтобы соответствовать данным в ОЗУ
- Используйте максимальную пиксельную тактовую скорость, которая до сих пор обеспечивает опрос PCLK SW.
Итак, я подошел к этой прикрепленной версии. Пиннинг задокументирован в файле INO.
Данные изображения отправляются в последовательный порт. Чтобы визуализировать его, сначала скопировал серийный вывод в Notepad ++, затем использовал Hex конвертер плагина->Асии. Сохранил данные как IMG.сырой.
Тогда я использовал ImageJ (http: // ImageJ.Национальные институты здравоохранения США.Gov/IJ/Download/Win32 ... Re8-64.молния), Файл->Импорт->RAW, 80 (линии) x160 (пиксели), 8 бит.
Я также прикрепил записанную картинку в пакет для справки.

Веселиться!

пса. Следующим шагом будет представление о изображении на STM32 :)

Rogerclark
Солнце 13 марта 2016 г., 21:40
Спасибо, Стив

Я знаю, что правильные настройки, кажется, нуждаются в какой -то магии вуду ;-)
(Потому что их так много)

Я уверен, что для STM32 было бы возможно DMA изображение с камеры, но я никогда не смог выяснить, как настроить все регситеры, которые понадобятся

Но хорошо, что у тебя есть что -то работающее.

Zoomx
Пн 14 марта 2016 г., 9:06
Irfanview тоже работает!
Изображение кажется 160x80, а не 80x160. Мой мозг OCR выход 3487!
Может быть, вы сможете сбросить отрывок, выводя бинарное изображение на сериал вместо ASCII HEX.

Ахулл
Пн 14 марта 2016 г., 9:15 утра
Вы могли бы выплюнуть .ppm который представляет собой простой сырой формат изображения, который поддерживают многие редакторы изображений, или если вам просто нужно ASCII-Plie его, то сначала просто приведите каждое значение HEX (половина скорости или около того, что они не были последовательными).

Больше информации здесь.

Стивестронг
Пн 14 марта 2016 г., 9:43 утра
@Ahull - спасибо, похоже, что формат PGM был бы настоящей альтернативой. Сторонная сумма данных будет немного больше, это, тем не менее, не имеет значения, потому что последовательные данные отправляются после того, как изображение было впервые записано во внутренней массиве буфера.

@zoomx - используемая настройка камеры позволяет 160 (пиксели) x 120 (линии), из которых я использую только первые 80 линий, полученная геометрия изображения подходит для моей потребности.

@Roger - я также думал о том, чтобы использовать DMA, но до тех пор, пока не нуждается в высокой частоте кадров (только одна устойчивая картина), я наконец реализовал самое простое решение.
В любом случае, для использования DMA не кажется намного сложным (теоретически), хитрость заключается в том, чтобы настроить таймер в режиме запуска рабов (я думаю), чтобы создать прерывание для DMA, когда обнаруживаются восходящие края PCLK. Для этого камера должна быть установлена ​​на создание PCLK только тогда, когда HREF активен (у меня есть соответствующая строка, прокомментированная в файле INO).

Rogerclark
Пн 14 марта 2016 г., 9:45
Стивестронг написал: Для этого камера должна быть установлена ​​на создание PCLK только тогда, когда HREF активен.

Стивестронг
Пн 14 марта 2016 г., 9:49
Нет, настройка по умолчанию - непрерывно генерировать PCLK.
Соответствующая команда:
// wrerg (reg_com10, bit5); // pclk не переключается на hblank
прокомментировал в моем файле ino.

Rogerclark
Пн 14 марта 2016 г., 10:00 утра
ХОРОШО

Спасибо. Это хорошо знать

jlsilicon
Вторник 3 мая 2016 г. 15:37
OV7670 предположительно успешно использован на Arduino.
Я пытался получить этот функционал на Arduino (но еще не).
Я был бы рад попробовать это на моих досках eBay STM32.

Ниже приведена ссылка:

https: // форум.Ардуино.CC/INDEX.PHP?Тема = 159557.720

Код должен быть легко конвертировать из Arduino в STM32.

Ниже приведен код Arduino и схема, без необходимого преобразователя уровня для PCLK.

Стивестронг
Вторник 3 мая 2016 г., 16:22
@jlsilicon
Я не уверен, в чем был твой вопрос.
Вы читали предыдущие сообщения?
Это дает вам больше информации, включая код:
http: // www.STM32duino.com/viewtopic.PHP?F = 19&t = 4#P11278

jlsilicon
Вторник 3 мая 2016 г., 16:41
Код Arduino OV7670 размещен здесь, чтобы предоставить возможный полезный дополнительный код поддержки - для кода STM32, предоставленного на этой предыдущей странице
- Для любого заинтересованного.

Например, пример примера STM32, указанный здесь, предоставляет только разрешение 160x80,
- В то время как код Arduino предоставляет режимы VGA 640/320x240 - которые могут быть полезными изменениями.

Я только что опубликовал это - и еще не выкопал свои доски STM32, чтобы попробовать это.
У меня также есть около 320x240 ILI9341 LCD, которые я могу использовать с ним.

Zoomx
Ср. 04 мая 2016 г. 15:05
Вы говорите о модулях с FIFO или без FIFO?

jlsilicon
Чт 5 мая 2016 г. 15:02
Без FIFO.
- Просто OV7670 подключен к плате eBay STM32F103C8.

Концзакп
SAT 22 апреля 2017 г. 12:41
Вы, ребята, видели это?
https: // www.YouTube.com/watch?V = TQSY6FETUOS
Он сделал огромную вещь 10 кадров в секунду на Arduino.
Я буду пытаться запустить его на Maple Mini.
У него есть весь код на GitHub также для STM!
Стоит попробовать!

Ахулл
SAT 22 апреля 2017 г. 16:23
Концзакп написал:Вы, ребята, видели это?
https: // www.YouTube.com/watch?V = TQSY6FETUOS
Он сделал огромную вещь 10 кадров в секунду на Arduino.
Я буду пытаться запустить его на Maple Mini.
У него есть весь код на GitHub также для STM!
Стоит попробовать!

Горан.маховик
Пт, 09 июня 2017 г. 13:45
Этот код выглядит действительно чистым, я попробую с моей камерой ...

https: // github.com/rodiongork/stm32f030-camera

Rogerclark
Пт, 09 июня 2017 г. 9:19 вечера
У меня тоже есть одна из этих камер.

Если у меня будет шанс, я тоже попробую.

Zoomx
Чт 15 июня 2017 г. 12:21
https: // github.com/indrekluuk/liveov7670_stm32-arduino
Использование дисплея на основе ST7735.

Это на базе Arduino Nano.
https: // github.com/indrekluuk/liveov7670

Rogerclark
Чт 15 июня 2017 г., 23:41
Я выкопал обе свои камеры OV7670.

У меня есть один с и один без ФИФО.

Я не уверен, какую версию использует эти репо, но я могу узнать.

Из того, что я помню, FIFO не очень помогает в захвате изображения, так как вам все еще нужно читать данные с очень высокой скоростью, однако я предполагаю, чтобы отправить кадр по медленной ссылке E.глин. USB Serial, может быть возможно захватить один кадр до FIFO, а затем прочитать этот кадр несколько раз, компенсируя одну дополнительную линию каждый раз, когда FIFO читается (и только чтение одной строки)

Но я также не могу вспомнить, держит ли FIFO целый кадр или линию списка 1, но это большой буфер (384K)
http: // www.averlogic.com/pdf/al422b_flyer.PDF

Так что я полагаю, это целый кадр.

Концзакп
Пт 16 июня 2017 г. 6:27
Репо Индреклуук использует камеру без FIFO. Кроме того. Это невозможно на Maple Mini, потому что отсутствует одна булавка PB9. Использование некоторого другого PIN (вместо PB9) вызывает больше циклов процессора для получения данных, и это вызывает более низкую скорость скорости кадров

Rogerclark
Пт 16 июня 2017 г., 7:45
Концзакп написал:Репо Индреклуук использует камеру без FIFO. Кроме того. Это невозможно на Maple Mini, потому что отсутствует одна булавка PB9. Использование некоторого другого PIN (вместо PB9) вызывает больше циклов процессора для получения данных, и это вызывает более низкую скорость скорости кадров

Стивестронг
Пт 16 июня 2017 г. 8:29 утра
https: // github.com/indrekluuk/liveov767 ... 7670.h#171 // configure PA8 to output PLL/2 clock #ifndef OV7670_INIT_CLOCK_OUT #define OV7670_INIT_CLOCK_OUT \ gpio_set_mode(GPIOA, 8, GPIO_AF_OUTPUT_PP); \ *(volatile uint8_t *)(0x40021007) = 0x7 #endif

Rogerclark
Пт 16 июня 2017 г. 9:45
Стивестронг написал:https: // github.com/indrekluuk/liveov767 ... 7670.h#171 // configure PA8 to output PLL/2 clock #ifndef OV7670_INIT_CLOCK_OUT #define OV7670_INIT_CLOCK_OUT \ gpio_set_mode(GPIOA, 8, GPIO_AF_OUTPUT_PP); \ *(volatile uint8_t *)(0x40021007) = 0x7 #endif

Стивестронг
Пт 16 июня 2017 г. 10:51
Обусловлен #ifdef _VARIANT_ARDUINO_STM32_

Rogerclark
Пт 16 июня 2017 г., 21:45
Стивестронг написал:Обусловлен #ifdef _VARIANT_ARDUINO_STM32_

Концзакп
SAT 17 июня 2017 г. 7:55 утра
Чтобы собрать это, вы должны добавить в компилятор.CPP.Флаги: -STD = GNU ++ 11 -O2

Rogerclark
Сб 17 июня 2017 г., 7:57 утра
Концзакп написал:Чтобы собрать это, вы должны добавить в компилятор.CPP.Флаги: -STD = GNU ++ 11 -O2

Концзакп
SAT 17 июня 2017 г. 11:22 утра
Важно, чтобы добавить -O2 после -os. Другим способом не будет компилировать.

Rogerclark
Сб 17 июня 2017 г. 12:01
Концзакп написал:Важно, чтобы добавить -O2 после -os. Другим способом не будет компилировать.

Концзакп
Сб 17 июня 2017 г. 12:24
Может ты прав. Он будет компилироваться, но не будет работать. Я не помню, что прошло много времени с тех пор, как я пытался.

Rogerclark
Сб 17 июня 2017 г. 12:38
хорошо

Если STD 11 отсутствовал, это не компилируется.

И, возможно, без -O2 он работает слишком медленно.

КСТАТИ.
Я вижу много активности использования DMA для записи данных в SPI и т. Д., Но DMA также может читать и писать в GPIO.
Таким образом, можно использовать DMA для чтения пикселей, без необходимости кода со всеми AMS NOPS

Стивестронг
Сб 17 июня 2017 г. 12:43
Rogerclark написал: Таким образом, можно использовать DMA для чтения пикселей, без необходимости кода со всеми AMS NOPS

Rogerclark
Сб 17 июня 2017 г., 21:31
Стивестронг написал:Rogerclark написал: Таким образом, можно использовать DMA для чтения пикселей, без необходимости кода со всеми AMS NOPS

Rogerclark
Солнце 18 июня 2017 г. 10:35
[Концзакп - Сб 17 июня 2017 г. 7:55] - Чтобы собрать это, вы должны добавить в компилятор.CPP.Флаги: -STD = GNU ++ 11 -O2
Вы можете вспомнить, как вы его подключили.

Я вижу в репо GitHub, что говорит.. Подключения камеры

A8 - XCLCK (часы камеры)
PB3 - hREF (соединение этого не является обязательным. Код не использует его)
PB4 - PCLCK (Pixel Clock)
PB5 - VSYNC (вертикальная синхронизация)
PB6 - часы I2C (резистор 10K до 3.3 В)
PB7 - Данные I2C (резистор 10K до 3.3 В)
PB8..PB15 - D0..D7 (пиксельный байт)

(У меня нет такого дисплея, поэтому мне нужно сделать что -то другое.глин. Показать в ILI9341 как -то)


Вы точно следовали этой проводке ?

Глядя на последний раз, когда я попробовал это. Я подключил два соединения IC2 до 3.3 В через 4.7k, но, возможно, это слишком много подтягивания.

Концзакп
Солнце 18 июня 2017 г. 11:05
Вот как я это связал:
TFT : STM32 GND : GND VCC : +5v Reset : PA1 A0 : PA3 SDA : PA7 SCL : PA5 CS : PA2 LED + : 3.3v LED - : GND CAMERA : STM32 reset : +3.3v pwdn : GND D0 : PB8 D1 : PB9 D2 : PB10 D3 : PB11 D4 : PB12 D5 : PB13 D6 : PB14 D7 : PB15 xclk : PA8 pclk : PB4 href : not connected vsync : PB5 sido : PB7 -> 10K resistor to 3.3V sidc : PB6 -> 10K resistor to 3.3V gnd : gnd vcc : +3.3v

Rogerclark
Солнце 18 июня 2017 г. 9:26 вечера
Хорошо.

Мне не удалось иметь время, чтобы подключить его вчера, так как форум BBS занял гораздо больше времени, чем ожидалось.

Я постараюсь сегодня подключить его к синей таблетке

астер
Солнце 18 июня 2017 г. 22:05
+1
(+∞, если вы сделаете это очень простым в использовании :рулон: )

Rogerclark
Пн 19 июня 2017 г. 1:06
Если я смогу заставить его работать с синей таблеткой и дисплеем ILI9341, я, вероятно, получу несколько печатных плат

Я также думаю о том, чтобы в целом создавать печатную плату, которая имеет подключения к синим таблеткам и сенсорному экрану ILI9341 Дисплей + SD

Rogerclark
Вт 20 июня 2017 г. 12:31
Просто быстрое обновление

Я подключил свою бессмысленную OV7670 к синей таблетке (много проводов), а также подключил ILI9341 (еще больше проводов)

Я собрал источники LiveOV7670STM32, не изменяя настройки оптимизации (пока), и изменил код, чтобы я использовал Adafruit ILI9341 LIB вместо библиотеки ST7735

Я также начал менять код так, чтобы строки сканирования отправлялись в ILI9341 по -другому в ST7735, и я начинаю видеть, что выглядят на дисплее, хотя длина линии сканирования не совпадает ILI9341, и я не устанавливаю позицию линии, а также я отправляю только RAW 8 -битные данные с камеры, когда я думаю, что дисплей ожидает 16 бит на пиксель, следовательно, изображение 2 света в моем потолке выглядит так ;-)
OV7670_ili9341.jpg
OV7670_ili9341.JPG (66.14 киб) просмотрено 769 раз

Rogerclark
Ср 21 июня 2017 г. 8:28
Я сделал еще кое -что с этим, но происходят странные вещи.

В коде отображения, кажется, есть NOPS, что я нахожу действительно странным.

И когда я пытаюсь просто использовать SPI.DMASEND (), чтобы поместить линейный буфер с камеры в ЖК -дисплей, добавив код в функцию, прежде чем он вызовет dmasend (), вызывает отображение изображения по -разному

Возможно, именно поэтому может понадобиться вариант компиляции -O2, но, вероятно, не помогает мне работать с ILI9341

Поскольку камера установлена ​​на запуск как QQVGA, а дисплей - QVGA, я попытался изменить код камеры для выполнения QVGA 320x240, дублировав класс BufferedCameraov7670_QQVGA, чтобы сделать BufferedCameraov7670_QVGA (и изменил значения)

Но если я попытаюсь отправить пиксельный буфер на дисплей, он, кажется, сбой кода.

Глядя на математику по ставкам данных. Код читает в данных в 8 м байтов за секунду (от пиксельных часов 8 МГц как шириной 8 бит)

Но его можно отправить на дисплей только в 36 МГц, а также накладные расходы на установку SPI.

Итак, единственный способ, которым я вижу, это работа, это использование разных линий из каждого кадра.

я.E камера камеры 1 Используйте строку 1 и отправьте на дисплей, затем дождитесь следующей кадры камеры, прочитайте только строку 2 и отправьте ее на дисплей

Но это приводит к действительно низкой частоте кадров.

Так что, возможно, какая -то более сложная схема сработает, e.глин. Прочитайте каждую 4 -ю линию камеры и отправляйте ее на дисплей, а затем смещается по 1 линии каждый кадр % 4

Пито
Ср 21 июня 2017 г. 9:05
Только идея - долгое время назад я перепутал с модулем Ramdisk - 8 МБ один, с только 11 сигналами - 8data и 3controls (плюс 3.3V и GND).
Он использовался с RetroBSD в качестве Swap и Ramdisk. Макс RD/WR скорость около 10 МБ/с. Может быть, полезно в качестве буфера кадров??

Rogerclark
Ср 21 июня 2017 г. 10:06
@pito

У меня также есть тип OV7670, который имеет буферный чип FIFO на спине. Averlogic al422b-pbf
http: // www.оно.Рит.CMU.Edu/Projects/Buzz ... Простыни.PDF

Насколько я могу судить, должно быть возможно написать один кадр с камеры, на 8 МГц, но затем переключить часы на 1 МГц, чтобы прочитать данные из FIFO

Или если это не работает, просто прочитайте линию фрейма по линии, я.E 1 линия за кадр, хотя это было бы намного медленнее

Пито
Ср 21 июня 2017 г. 10:50 утра
Не могли бы вы транслировать видео из модуля с FIFO на SDCARD, например, с более низким разрешением?

Rogerclark
Ср 21 июня 2017 г. 11:13
Я думал, что я мог бы уже выбирать данные.

Но я надеялся получить полное изображение QVGA 320x 240 на ILI9341
Однако в настоящее время цвета все неправильно, и я не знаю, правильно ли инициализируется камера.

Код, кажется, инициирует камеру и сообщает, что все в порядке, вполне возможно, что он на самом деле не полностью инициализирован полностью правильно

Я думаю, что единственный способ я могу проверить это - это заказать модуль ST7735 с eBay
Возможно, этот модуль

http: // www.eBay.компонент.AU/ITM/1-8 дюймов-1-8 ... 2456943464

А затем компилируйте и запустите код, используя этот дисплей, и подтвердите, что все работает OK.

А затем попытайтесь получить работу ILI9341
Пса. Отладка - это боль. он вызывает «без прерываний», поэтому USB останавливается. А также отладка в реальном времени, подобные этому, сложно, если полагается на странные времена.

Мне, вероятно, придется отлаживать, отправив данные в серийный порт

Я могу взглянуть на использование Daniel's STM32GENERIER и библиотеки STM DMA, чтобы, возможно, попробовать DMA's GPIO в ОЗУ, а не использование кода, полного NOPS

Пито
Ср 21 июня 2017 г. 11:16
К вашему сведению - есть несколько модификаций 7735 TFT - зеленый, черный, красный, ..и т. д. Они отличаются тем, как они интерпретируют цвета, например,..

Концзакп
Ср 21 июня 2017 г. 11:51
Правильно, они различаются, но в коде легко измениться, как инициализируется экран. Есть что -то вроде экрана init с blacktab greentab и т. Д.

Rogerclark
Ср 21 июня 2017 г. 22:43
[Концзакп - Ср 21 июня 2017 г. 11:51] - Правильно, они различаются, но в коде легко измениться, как инициализируется экран. Есть что -то вроде экрана init с blacktab greentab и т. Д.
Хорошо.
Я заказал два из этих дисплеев для тестирования

КСТАТИ. Если вы компилируете без опции -O2, можете ли вы сказать мне, если он все еще не работает, если вы используете последнюю версию репо ?

На данный момент я получаю совершенно неверные цвета, которые могут быть связаны с неправильной настройкой камеры, но могут быть побочным продуктом данных, которые не работают правильно из камеры из-за проблем с времени

Концзакп
Чт 22 июня 2017 г., 7:04
С последней версией репо, когда вы собираетесь компиляция без -O2, вы получите беспорядок на экране (вы увидите движение пикселей, но он не даст вам надлежащего изображения, я также вижу, что экран разделен на два и оба раздела показывают одинаковый вид беспорядка). В коде также есть что -то вроде этого:
void initLiveOV7670() { bool cameraInitialized = camera.init(); tft.initR(INITR_BLACKTAB); if (cameraInitialized) { tft.fillScreen(ST7735_BLACK); } else { tft.fillScreen(ST7735_RED); delay(3000); }

Rogerclark
Чт 22 июня 2017 г., 7:13 утра
Призыв к init, камера, кажется, возвращается, что она преуспела, но цвета испорчены

Я знаю, почему я получаю 4 изображения на экране. Это потому, что камера записывается в QQVGA, а экран qvga

Я попытался изменить код, чтобы привлечь камеру для записи как QVGA (320x240), но когда я пытаюсь отправить эти данные в ILI9341, он вылетает, и я не уверен, почему

Я попробую перекомпилировать с оптимизацией -O2.

Мне также нужно посмотреть на код, чтобы понять, как он должен работать, так как функция записать пиксели на экране очень очень медленная, и я не понимаю, почему в нем есть NOPS

Концзакп
Чт 22 июня 2017 г., 7:24 утра
Если это поможет как -то:

Пиксели с камеры отправляются в формат два байта RGB565.
first byte: R - PB15 R - PB14 R - PB13 R - PB12 R - PB11 G - PB10 G - PB09 G - PB08 second byte: G - PB15 G - PB14 G - PB13 B - PB12 B - PB11 B - PB10 B - PB09 B - PB08

Rogerclark
Чт 22 июня 2017 г. 11:19
Я думал, что это был тот же формат, что и дисплей ILI9341, но, возможно, это не

https: // cdn-shop.Адафрут.com/dataheets/ili9341.PDF

Я думаю, что формат данных находится на странице 45


Я думал, что это было 565, как камера, но мне нужно дважды проверить

Стивестронг
Чт 22 июня 2017 г., 11:45
Кажется, это 565, но читайте в большом формате Endian (сначала высокий байт).
Если вы храните его как uint16_t и напишите на дисплее в Little Endian, то цвета, конечно, будут разными.

Rogerclark
Чт 22 июня 2017 г. 11:54
[Стивестронг - Чт 22 июня 2017 г. 11:45] - Кажется, это 565, но читайте в большом формате Endian (сначала высокий байт).
Если вы храните его как uint16_t и напишите на дисплее в Little Endian, то цвета, конечно, будут разными.
Я на самом деле пытался построить буфер и байт, но это, казалось, ухудшило ситуацию.

ILI9341 также, по -видимому, имеет эндский выбор (стр. 192 DOC)

Таким образом, может быть возможно поменять его так, что это так же, как камера

Стивестронг
Чт 22 июня 2017 г. 13:54
Хорошо, тогда я могу думать только на неправильных данных конфигурации (YUV вместо RGB), либо в ошибочном канале связи, который приводит к неправильной конфигурации.

Rogerclark
Чт 22 июня 2017 г. 22:38
Я постараюсь собирать оптимизацию -O2 и посмотрю, изменится ли что -нибудь.

И если это не исправят цвета, я подожду, когда наступит дисплей 7735, потому что его будет намного проще работать с ILI9341, когда я точно знаю, что камера выводит RGB .

Rogerclark
SAT 24 июня 2017 г. 12:00
Я попытался компиляция с -O2 вместо -OS, и это не сделало дисплей лучше, однако скорость кода должна быть намного быстрее, потому что теперь я вижу только 2 изображения вертикально на экране, а не 4

Кроме того, если у меня есть Byteswap, я получаю лучшие цвета, но похоже, что есть что -то странное с захватом изображения или отправкой данных на дисплей.

Потому что порядок байта, кажется, меняется попеременно между линиями
ov7670_byteswap.jpg
ov7670_byteswap.JPG (91.22 киб) просмотрено 335 раз

Rogerclark
SAT 24 июня 2017 г. 2:10
Прежде всего, я не уверен, почему это работает, но я обещаю вам, что это ;-)

Я меняю свой код, чтобы я обменивался байтом и дублировал пиксели вниз по линии, а также дважды отправляю одну и ту же строку на дисплей
uint8_t dispBuf[320*2]; uint8_t b1; uint8_t *tdBufEnd = dispBuf + 320*2; void sendLineToDisplay() { // if (screenLineIndex-- > 0) { uint8_t *cBufPtr = (uint8_t *)camera.getPixelBuffer(); uint8_t *tdBuf = dispBuf; while(tdBuf < tdBufEnd) { b1=*cBufPtr++; *tdBuf++=*cBufPtr; *tdBuf++=b1; *tdBuf++=*cBufPtr++; *tdBuf++=b1; } SPI.dmaSendAsync((uint8_t *)dispBuf,camera.getPixelBufferLength()); SPI.dmaSendAsync((uint8_t *)dispBuf,camera.getPixelBufferLength()); } }

Концзакп
SAT 24 июня 2017 г. 6:53
С этой проблемой артефактов (фиолетовых или каких -либо других и странных цветов), я думаю, вы могли бы решить это с настройкой в ​​основном файле в настройке всех контактов данных в режим ввода. Кажется, что один вывод данных не функционирует, как следует. Попробуйте.

Rogerclark
SAT 24 июня 2017 г. 7:07
[Концзакп - SAT 24 июня 2017 г. 6:53] - С этой проблемой артефактов (фиолетовых или каких -либо других и странных цветов), я думаю, вы могли бы решить это с настройкой в ​​основном файле в настройке всех контактов данных в режим ввода. Кажется, что один вывод данных не функционирует, как следует. Попробуйте.
ХОРОШО

Я мог бы иметь сухой соединение, плохое соединение

Я напишу немного тестового кода, чтобы прочитать PB IDR и посмотрю, всегда ли один из битов нулевым

Стивестронг
SAT 24 июня 2017 г. 7:07
Необходимость изменения байтового обмена будет означать, что вы фактически теряете байт (полпиксель) от одной линии к другой, которую вы каким -то образом восстановите на следующей строке.

Rogerclark
SAT 24 июня 2017 г. 7:12
[Стивестронг - SAT 24 июня 2017 г. 7:07] - Необходимость изменения байтового обмена будет означать, что вы фактически теряете байт (полпиксель) от одной линии к другой, которую вы каким -то образом восстановите на следующей строке.
Я не должен терять половину пикселя
b1=*cBufPtr++; *tdBuf++=*cBufPtr++; *tdBuf++=b1;

Стивестронг
SAT 24 июня 2017 г. 7:55 утра
Может ли проигрыш произойти, прежде чем вы начнете копировать? Не знаю, просто спекулируют...

Rogerclark
SAT 24 июня 2017 г. 9:46
Возможно, что пиксельный буфер с камеры имеет недопустимые данные.

Тем не менее, я думаю, что @konczakp может быть правильным, и что, возможно, 1 данные не подключены.

Я прокомментировал линию, которая отключила прерывания, и использовал сериал.распечатать, чтобы зарегистрировать некоторые данные с камеры, и я думаю, что бит 3 всегда низко

эн.глин.
Некоторые данные FA FB FA FB FB FB FB FB FB FB FB EB F9 91 32 D3 52 BA 8B 99 48 91 3 78 83 70 22 78 23 70 3 6B E2 6B C1 6B 82 63 82 6B 42 63 42 5B 22 63 22 63 42 6B 63 73 62 73 62 6B 82 73 A2 73 E2 7B E2 7B C1 6B 60 6B 41 6B 61 80 29 80 49 78 8 80 28 7B E9 63 62 6B 29 7B AA 7B C9 7B EA 83 EA 7B A9 52 C1 42 23 0 C2 10 A2 10 82 10 82 10 82 10 82 10 82 10 82 10 82 8 82 8 82 10 82 10 A2 10 A3 10 A3 10 83 10 83 8 62 8 62 8 82 8 82 10 82 10 82 8 83 8 83 8 82 8 82 8 82 8 82 8 83 8 83 8 82 8 82 8 82 8 82 8 82 8 82 8 82 8 62 8 62 8 62 8 62 8 62 8 62 8 62 8 62 10 C3 11 1 10 E0 8 C0 0 FA FB FA FB FB FB FB FB FB FB FB D2 F9 A9 B0 99 CB 99 AA 91 4A 91 4A 89 4A 89 4A 89 9 89 9 88 E9 88 E9 80 C9 80 C9 80 A9 80 A9 88 A9 80 A9 80 A8 80 A8 80 89 88 89 88 89 80 88 80 68 80 43 80 48 80 28 80 43 80 48 88 A9 90 C9 78 8 80 28 78 A 6B 63 63 3 7B A9 73 C9 7B CA 7B C9 73 A9 52 C1 42 23 0 8 82 8 82 8 62 8 62 8 62 8 62 8 62 8 62 8 62 8 62 8 62 8

ZMEMW16
SAT 24 июня 2017 г. 11:20
это было бы намного проще с ', bin' в println : D
SRP

Rogerclark
SAT 24 июня 2017 г. 11:38
Попробовал бин, но это не ведущее нули

В любом случае

PB10, похоже, не вводит по умолчанию (не уверен, почему)

Так что я терял 1 бит входных данных, так как это всегда было нулевым

Я добавил дополнительный (отсутствующий) код инициирования
const int inputpins [] = {pb9, pb9, pb10, pb11, pb12, pb13, pb14, pb15};
для (int i = 0; i<8; i ++)
{
PinMode (InputPins,ВХОД);
}



Все еще немного вымыто, но он работает намного лучше

Может быть еще лучше при дневном свете, поэтому я сделаю еще одно видео завтра

@konczakp еще раз спасибо

Я, вероятно, должен сделать пиар в учетной записи авторов GitHub или, по крайней мере, решить проблему с этим исправлением !

Концзакп
SAT 24 июня 2017 г. 12:38
Без проблем. Мы все здесь, чтобы помочь друг другу :) В ожидании обратной связи о цветах в искусственном свете и в дневном свете. В моем случае только первый был правильным.

Пито
SAT 24 июня 2017 г., 19:19
PB10 по выпуску BP - http: // www.STM32duino.com/viewtopic.PHP ... = 30#P30136

Rogerclark
SAT 24 июня 2017 г. 11:04
[Пито - Сб 24 июня 2017 г., 19:19] - PB10 по выпуску BP - http: // www.STM32duino.com/viewtopic.PHP ... = 30#P30136
Спасибо

Я смутно вспомнил, что читал, что.

Я уверен, что это можно исправить с помощью некоторых операторов #IFDEF

Rogerclark
Солнце 25 июня 2017 г. 3:03
[Rogerclark - SAT 24 июня 2017 г. 11:04 PM] -
[Пито - Сб 24 июня 2017 г., 19:19] - PB10 по выпуску BP - http: // www.STM32duino.com/viewtopic.PHP ... = 30#P30136
Похоже, лучшее решение - определить
#define BOARD_USB_DISC_DEV NULL #define BOARD_USB_DISC_BIT NULL

Стивестронг
Солнце 25 июня 2017 г. 16:55
[Rogerclark - Солнце 25 июня 2017 г. 3:03] - Я подтолкнул к тому, чтобы исправить это для BP и нескольких других досок; однако у некоторых досок, кажется, есть другие булавки, определяемые как штифт отключения (не только Maple Mini), поэтому я оставил их нетронутыми, если люди люди Использование плат с оборудованием отключения
Повлияет ли это каким-либо образом на повторную рору USB после сброса на досках не-ММ?
Насколько я вижу, эта булавка именно то, что должно делать, и если вы настроите на NULL, он больше не будет сделан.
Но я, скорее всего, неправ.

Rogerclark
Солнце 25 июня 2017 г. 8:50 вечера
Afik Pin Pb10 не имеет ничего общего с USB. На BP это всего лишь штифт GPIO, не подключенный ни к чему.

Таким образом, для плат без дополнительного USB -оборудования, этот вывод не должен быть установлен для вывода во время функции USB включить.

Но я думаю, что, возможно, на такими досками, как BP, так что в USB -inable () (), но код был поставлен в сериал USB, по ошибке, потому что в то время единственным типом поддерживаемого USB -интерфейса был сериал USB

Стивестронг
Пн 26 июня 2017 г. 5:51 утра
Вернуться к часам...
Пожалуйста, объясните мне, что там происходит, я просто не понимаю.

Прежде всего, использует ли процессор SYSCLK?
Проходит ли процессор с 72 МГц?

Если я проверю RM0008 Рисунок 8 часов часов, я увижу источником Sysclk может быть HSI, PLLCLK или HSE.
HSI = 8 МГц.
HSE = 8 МГц (на BP).
Pllclk = ???

Является источником sysclk, установленного в Pllclk?
Означает ли это, что PLLCLK также 72 МГц?

OTOH, MCO выводит PLLCLK/2, который в любом случае является половиной часов процессора, справа?
Значит ли это, MCO выводит 36 МГц? Пиксельные часы = 36 МГц?

В любом случае, если часы процессора всего вдвое превышают часы пикселей, то я понимаю эти много NOPS. Они, скорее всего, обслуживают точное время для отбора данных данных о камере, но кажется, что процессор должен пробежать на каждом втором часах и не ждать с несколькими NOPS.

С другой стороны, если MCO = 8 МГц, это означает SYSCLK = 16 МГц, часы SPI = 8 МГц...

Где я ошибаюсь?

РЕДАКТИРОВАТЬ

Я думаю, что получил это.
Я смешал XCLK с PCLK.
Таким образом, кажется, что XCLK = 36 МГц (MCO), но PCLK = 8 МГц (или в конечном итоге 9 МГц), справа?
Вы измеряли это с прицелом?
В любом случае, нам нужны эти NOPS для оптимального считывания данных Pixel в середине периода PCLK.

Но если есть так много времени, чтобы подождать, почему бы не прочитать данные и вывести на дисплей сразу?

Rogerclark
Пн 26 июня 2017 г., 7:06 утра
Я проверю часы, используя мой логический анализатор

Re: чтение и написание одновременно.

Это было бы более эффективным для байтового обмена, когда он читает пиксели, а также для дубликата Pixel, и, возможно, даже дублировать линию в буфер.

Это оставило бы больше времени для проведения другой обработки, но на F103 или большинстве STM32 не станет возможным сделать много обработки, кроме, возможно, коррекции цвета, потому что обычно для того, чтобы делать такие вещи, как заточка и т. Д. Пиксели в направлениях X и Y можно получить.

Я не знаю, какие приложения существуют для простого потока видео на дисплей, кроме использования его в качестве предварительного просмотра перед сбором одного кадра в качестве неподвижного изображения.

Я полагаю, что это можно использовать для обнаружения движения с помощью какого -то контрольной суммы для каждой кадра (это было бы действительно битовым числом), возможно, за пределами 32 бит.

Rogerclark
Пн 26 июня 2017 г., 7:36 утра
ХОРОШО.
Я проверил, и XCLK показывает как 33 МГц на моем анализатора, но он должен означать 36 МГц (72 МГц /2)

Пиксельные часы, кажется, 2.25 МГц я.E Div16 36 МГц при 12 кадров в секунду

Если я заменим кадров, на 7.2 кадры в секунду, пиксельные часы изменяются на 1.51 МГц (я предполагаю, что это 36 МГц div24)

Вернуться на 12 кадров QQVGA

Между VSYNC и началом первой строки около 3 существует огромное количество времени.5 мс

Пиксельные часы снижаются в то же время, когда HREF поднимается на высоком уровне, и я думаю, что пиксель данных в кулаке станет так

Каждая строка в QQVGA длится около 143US, а затем есть немного разрыва до следующей строки, около 550us

Что было бы здорово, если бы мы могли использовать DMA для чтения порта GPIO B. На восходящем краю пиксельных часов

Но на синей таблетке данные пикселя считываются через PB8 до PB15 (верхние 8 бит), но нижние 8 бит будут лучше, но это потребует соединения с Boot1 (PB2)

Стивестронг
Пн 26 июня 2017 г. 9:07
Использование PB2 (boot1) не является проблемой, я использую его для 8 -битного параллельного вывода для платы отображения и работает, поэтому я предполагаю, что он также должен работать как вход. Просто то, что резистор, который подключен между перемычкой Boot1 и входным штифтом, должен быть сокращен.

Но можем ли мы запустить DMA на (поднимающемся/ошибке) края входного сигнала (PCLK)?
Я думаю, что мы могли бы подсчитать край входного сигнала с помощью таймера, установленного в режиме подчиненного триггера, который выход таймера может работать как источник триггера DMA, как я уже упоминал здесь: http: // www.STM32duino.com/viewtopic.PHP?F = 19&t = 4#P11307

Rogerclark
Пн 26 июня 2017 г. 11:30
[Стивестронг - Пн 26 июня 2017 г. 9:07] -

Но можем ли мы запустить DMA на (поднимающемся/ошибке) края входного сигнала (PCLK)?
Я думаю, что мы могли бы подсчитать край входного сигнала с помощью таймера, установленного в режиме подчиненного триггера, который выход таймера может работать как источник триггера DMA, как я уже упоминал здесь: http: // www.STM32duino.com/viewtopic.PHP?F = 19&t = 4#P11307
Да. Я подумал, что можно в основном запустить один передачу DMA на exti через таймер, но это звучит трудно настроить

Концзакп
Пн 26 июня 2017 г. 13:37
Вы пробовали камеру в разных источниках света? Цвета выглядят одинаково? Как это?

Стивестронг
Пн 26 июня 2017 г., 17:56
Я заказал 2 модуля камеры (2.35 евро за штуку).
Я протестирую программное обеспечение, когда эти модули появятся.

Indrekluuk
Пн 26 июня 2017 г. 18:11
Привет! Я автор проекта LiveOV7670_stm32-arduino. Я нашел эту тему по Googling.


Ранее был вопрос о том, почему у меня есть «ASM нестабильный (« NOP »);»; В методе, который отправляет пиксели на экран.
Причина в том, что SPI.передача (байт); ужасно медленно, и это просто талия:
Изображение

Но когда я просто установил регистр SPI TX и немного подожду, прежде чем установить следующий байт, он выглядит так
Изображение


Было также несколько разговоров о разрывах между линиями. Вот как выглядят линии сканирования с QQVGA@12HZ:
Изображение
Синий - это пиксельные часы с камеры.
Желтый - это часы SPI на экране.



В коде Arduino Uno я смог получить 10 кадров в секунду, потому что он был в идеальной синхронизации с камерой. Я мог бы обнаружить первый падающий край пиксельных часов, а затем слепо прочитать остальную часть линии, не проверяя пиксельные часы. По какой -то причине я не смог этого сделать с STM32. Я считаю, что QQVGA@30 Гц должен быть возможен с STM32, если бы я мог получить чтение пикселей, идеально синхронизированное.

Стивестронг
Пн 26 июня 2017 г., 19:52
@indrekluuk,
Спасибо за информацию.
Действительно, вызов передачи SPI для каждого байта частично не очень хорошая идея.
Но у нас есть эффективные процедуры Multi-Byte Spi, с DMA и без него.
Итак, вы можете использовать SPI.написать (буфер, nr_bytes); Вместо того, чтобы называть SPI.Перенос много раз подряд.

Согласно вашему графику по объему, я предполагаю, что сохранение фактической структуры SW можно было бы удвоить FPS, не изменив ничего другого, кроме прескалера PCLK камеры. Период времени между поездом SPI записи и следующим поездом PCLK достаточно велик.

Rogerclark
Пн 26 июня 2017 г. 22:03
@indrekluuk

Спасибо за публикацию.

Возможно, я должен был поместить ссылку на эту ветку в своем ответе на ваш пост на YouTube.

Я использую дисплей ILI9341, который представляет собой QVGA, а также байт -порядок данных обращается вспять с того, что отправляет камера

Я делаю немного, если взлом, просто передавая весь пиксельный буфер из камеры на дисплей через временный буфер, используя функцию dmasend ().

Чтобы перейти от QQVGA до QVGA I Pixel Byte Swap и дублирующих пикселей из пиксельного буфера в мой временный буфер, затем дважды отправьте одну и ту же линию.

Я попытался переключиться на QVGA с камеры, но при 12 кадров в секунду я не могу отправить на дисплей достаточно быстро, потому что не хватает скорости передачи данных, поскольку максимальная скорость SPI составляет 36 млн бит в секунду, но скорость передачи данных камеры в QVGA выше.

Но я думаю 7.2 FPS QVGA технически возможна.

@pito также предложил Changjng основной PLL дать 80 МГц, а затем SPI в ILI9341 будет 40 МГц, но даже при этом я не уверен, что QVGA при 12 кадров в секунду будет возможна.

Я могу переместить ввод данных в PB0 в PB7 (это требует подключения к заголовку Boot1, но это нормально)

Тогда должно быть возможно, чтобы показать данные с камеры через DMA.

Пито
Вт 27 июня 2017 г. 5:51 утра
Кстати, DataSheet ILI9341 говорит, что часы SPI «написать» должны быть максимум 10 МГц..
https: // cdn-shop.Адафрут.com/dataheets/ili9341.PDF

Rogerclark
Вт 27 июня 2017 г. 6:01
[Пито - Вт 27 июня 2017 г. 5:51]] - Кстати, DataSheet ILI9341 говорит, что часы SPI «написать» должны быть максимум 10 МГц..
https: // cdn-shop.Адафрут.com/dataheets/ili9341.PDF
РЖУ НЕ МОГУ

Мы уже запускаем его на 36 МГц :ржу не могу:

Пито
Вт 27 июня 2017 г. 6:26 утра
Итак, вы уже разгоняете :) Таким образом, запуск BP на 128 МГц не может быть проблемой для вас :)
Я думаю, что для игры с видео и вашего намерения сделать некоторую обработку изображений Black F407Zet плюс 512-1024 КБ Внешний SRAM-минимум. F407 даже обладает DCMI..

Стивестронг
Вт 27 июня 2017 г. 6:43
[Пито - Вт 27 июня 2017 г. 6:26 утра] - F407 даже обладает DCMI..
Это звучит как легкая работа.
Но где тогда вызов? 8-)

Indrekluuk
Вт 27 июня 2017 г. 18:53
[Стивестронг - Пн 26 июня 2017 г., 19:52] - @indrekluuk,
Спасибо за информацию.
Действительно, вызов передачи SPI для каждого байта частично не очень хорошая идея.
Но у нас есть эффективные процедуры Multi-Byte Spi, с DMA и без него.
Итак, вы можете использовать SPI.написать (буфер, nr_bytes); Вместо того, чтобы называть SPI.Перенос много раз подряд.
Я проверил. SPI.Написать (const uint8 *data, uint32 длина) лишь незначительно лучше, чем вызов SPI.перевести один за другим.
Изображение

Стивестронг
Вт 27 июня 2017 г., 19:02
Я проверил ваш код, и кажется, что он использует только байтовые письма, а не буферированные много-байтовые письма. Скажите, пожалуйста, если я ошибаюсь.
В этом случае вы можете использовать: SPI.write(uint8 data);

Indrekluuk
Вт 27 июня 2017 г., 8:28 вечера
Последний тест (изображение осциллографа http: // imgur.com/q4fz9lv) был сделан с этим: void sendLineToDisplay() { if (screenLineIndex > 0) { screenLineStart(); SPI.write(camera.getPixelBuffer(), camera.getPixelBufferLength()); screenLineEnd(); } }

Indrekluuk
Вт 27 июня 2017 г. 8:35 вечера
Я добавил BufferedCameraov7670_Qvga в GitHub. Я получил QVGA, работающий до 7.5 кадров в секунду.
У меня нет экрана QVGA, но я смог четко отобразить четверть изображения на моем меньшем экране.

Rogerclark
Вт 27 июня 2017 г., 21:27
Индивидуальный байт пишет в SPI не так быстро

Я использую dmasend () целую линию за раз

Редактировать.

У меня есть QVGA

Я скачаю позже

Indrekluuk
Ср 28 июня 2017 г. 5:18 утра
РЕДАКТИРОВАТЬ:
Извините, кажется, что это переверсит бит, и у меня уже есть метод для этого.


Rogerclark, я только что проверил DataShing OV7670 (https: // www.голосование.NL/DOCS/OV7670.PDF)
OV7670 имеет бит регистра, который обменяется байтами пикселей:

Изображение

Вам не нужно писать какие -либо взломы, чтобы поменять байт -заказ. Я добавлю метод в класс CameraV7670, который устанавливает этот реестр, когда я вернусь домой вечером.

Rogerclark
Ср 28 июня 2017 г. 10:46
Отличный

Я смотрел в спецификацию для камеры, но она описала байты как «нечетные» и «даже», и я не смог найти никаких других функций, которые сказали, что они изменили этот или байт -заказ.

Это сэкономит много обработки и определенно поможет с уровнем данных.

Но я думаю 7.2FPS в QVGA настолько быстрая, насколько технически возможна, потому что скорость передачи данных на дисплее ILI9341, даже при разгрузке до 36 МГц (Мбит / с) медленнее, чем QVGA с камеры при 12 кадров в секунду

Стивестронг
Ср 28 июня 2017 г. 11:52
Роджер, будьте осторожны, похоже, что в руководстве пользователей упомянуто в руководстве по пользователям MSB / LSB на самом деле бит реверсирование (D0 -> D7, D1->D6, ...), а не обмен на байт!
OV7670 Data Swap.jpg
OV7670 Обмен данных.JPG (46.34 киб) просмотрено 269 раз

Стивестронг
Ср 28 июня 2017 г. 12:07
@indrekluuk,
Можете ли вы сказать нам, какой драйвер SPI вы используете? Это из официального репозитория arduino_stm32?
https: // github.com/rogerclarkmelbourne/ ... ES/SPI/SRC
https: // github.com/rogerclarkmelbourne/ ... /spi.C#L95
Потому что это должно быть получено намного лучше, чем то, что вы измерили.
Если я использую "SPI.написать (buf, nr_bytes) "Функция, часы SPI практически непрерывны.

Indrekluuk
Ср 28 июня 2017 г. 8:23 вечера
@stevestrong

Я использую Platformio для компиляции и загрузки.

На быстром взгляде кажется, что библиотека SPI, которая поставляется с Platformio, является следующей:
https: // github.com/rogerclarkmelbourne/ ... ES/SPI/SRC

Rogerclark
Ср 28 июня 2017 г. 9:53 вечера
[Indrekluuk - Ср 28 июня 2017 г. 8:23 вечера] - @stevestrong

Я использую Platformio для компиляции и загрузки.

На быстром взгляде кажется, что библиотека SPI, которая поставляется с Platformio, является следующей:
https: // github.com/rogerclarkmelbourne/ ... ES/SPI/SRC
Я использую ILI9341, и выгода от этого, по -видимому, заключается в том, что я могу DMA Whole Lines через SPI.
На данный момент мне приходится обмен байтором после завершения пиксельного буфера, но было бы легко изменить код, который захватывает пиксели с камеры, так что он выполняет байтовый своп, когда данные помещают в буфер.
(Мне может потребоваться изменить количество NOPS, если это немного замедлит код, но есть много NOP, так что есть некоторые, чтобы сделать некоторую арифметику указателя, и возможно, что набор инструкций ARM имеет методы для *( PTR + 1))

Стивестронг
Ср 28 июня 2017 г. 22:08
Насколько я знаю, @indrekluuk использует трюк, который игнорирует самый первый байт, так что высокий байт следующего пикселя будет высоким байтом фактического пикселя.

Я не знаю, поможет ли это, если вы установите режим SPI на 16 -битный перевод? Изменять ли байты свой порядок таким образом?

Rogerclark
Ср 28 июня 2017 г. 11:32
[Стивестронг - Ср 28 июня 2017 г. 22:08] - Насколько я знаю, @indrekluuk использует трюк, который игнорирует самый первый байт, так что высокий байт следующего пикселя будет высоким байтом фактического пикселя.

Я не знаю, поможет ли это, если вы установите режим SPI на 16 -битный перевод? Изменять ли байты свой порядок таким образом?
Я думал об этом трюке, но я не думаю, что это работает ?

Разве вы не получите высокий байт Pixel1 и низкий байт Pixel 2, который считается первым байтом, отправленным на дисплей.

Если это то, что я думаю, вы говорите, то есть большая проблема, потому что канал зеленого цвета разделен на дно одного байта и верхнюю часть следующего, поэтому зеленый канал для результирующего пикселя представляет собой смесь 2 байта, и могут быть совершенно неправы, если значение сильно изменится от пикселя на пиксель E.глин. Проходит по порогу, где две половины зеленого канала разделены по байтам.

Стивестронг
Чт 29 июня 2017 г. 6:33
[Rogerclark - Ср 28 июня 2017 г. 11:32] - Разве вы не получите высокий байт Pixel1 и низкий байт Pixel 2, который считается первым байтом, отправленным на дисплей.
Точно, это хитрость, если я правильно интерпретирую вещи здесь: https: // github.com/indrekluuk/liveov767 ... 7670.H#L17
Проблема с зеленым цветом, который, как я думаю, имеет решающее значение, так как верхние 3 бита из правильного пикселя, нижние 3 бита не оказывают большого влияния на цвет в сочетании с красным и синим каналом.
Единственное, что - это последняя половина пикселя, которым пренебрегают, я думаю. Но это на краю, поэтому не беспокоит, если у него нет правильного цвета.

Indrekluuk
Чт 29 июня 2017 г. 6:38 утра
[Стивестронг - Ср 28 июня 2017 г. 22:08] - Насколько я знаю, @indrekluuk использует трюк, который игнорирует самый первый байт, так что высокий байт следующего пикселя будет высоким байтом фактического пикселя.
Вы правы. В настоящее время я «исправляю» пропавший первый байт, добавив 0 байт в начале. Это означает, что самый первый пиксель сломан.
Это потому, что не хватает времени, чтобы обнаружить края пикселей и прочитать пиксель в более высоких FPS. Может быть, если бы вы могли прочитать пиксель на уровне аппаратного обеспечения (я предполагаю, что это то, что делает DMA?) тогда проблема будет исправлена.

Теперь я увидел, что в спецификации есть «фиктивные пиксельные вставки MSB» и «Dumy Pixel INSERT LSB». Вероятно, можно решить первую проблему байта, добавив манекен -байт вначале, который будет игнорироваться.

Rogerclark
Чт 29 июня 2017 г., 6:45
Есть много времени, чтобы правильно обмен байтом.

Разве в коде нет много нопс ?

Indrekluuk
Чт 29 июня 2017 г., 6:47
[Стивестронг - Чт 29 июня 2017 г. 6:33] -
[Rogerclark - Ср 28 июня 2017 г. 11:32] - Разве вы не получите высокий байт Pixel1 и низкий байт Pixel 2, который считается первым байтом, отправленным на дисплей.
Точно, это хитрость, если я правильно интерпретирую вещи здесь: https: // github.com/indrekluuk/liveov767 ... 7670.H#L17
Проблема с зеленым цветом, который, как я думаю, имеет решающее значение, так как верхние 3 бита из правильного пикселя, нижние 3 бита не оказывают большого влияния на цвет в сочетании с красным и синим каналом.
Единственное, что - это последняя половина пикселя, которым пренебрегают, я думаю. Но это на краю, поэтому не беспокоит, если у него нет правильного цвета.
Просто чтобы уточнить. В настоящее время в коде пиксели в паре правильно. Заполнение в буфере добавляется, так как я пропускаю байт пикселя в кулаке при чтении с камеры. Это означает, что я не очищаю высокий байт пикселей 1 и низкий байт пикселя 2.

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

Rogerclark
Чт 29 июня 2017 г., 6:48
Ах ОК

Я думаю, что @stevestong подразумевал, что вы поменяете Эндиан Несс таким образом, с результирующей проблемой в зеленом канале

Indrekluuk
Чт 29 июня 2017 г. 7:10 утра
[Rogerclark - Чт 29 июня 2017 г. 6:45] - Есть много времени, чтобы правильно обмен байтом.

Разве в коде нет много нопс ?
Я должен немного подумать об этом (возможно, на выходных).
Я думаю, что можно получить свободный байтовый своп, если структура памяти определяется правильно. Поскольку PixelBuffer находится в статической памяти +1 -1 Расчеты с адресом буфера будут выполнены во время компиляции.

Что -то вроде этого: while (bufferIndex < (getPixelBufferLength() / 2)) { waitForPixelClockLow(); asm volatile("nop"); pixelBuffer.writeBuffer[bufferIndex++].highByte = readPixelByte(); waitForPixelClockLow(); asm volatile("nop"); pixelBuffer.writeBuffer[bufferIndex++].lowByte = readPixelByte(); }

Стивестронг
Чт 29 июня 2017 г. 8:23
@indrekluuk, извините, кажется, что я неверно истолковал ваш код, я хотя заполнение была там для байтового обмена.

После консультации с руководствами как OV7670, так и ILI9341 я вижу, что нет необходимости поменять байты.

OV7670 Вывод данных начинается с байта R+(G/2):
OV7670 Data Output.jpg
OV7670 Вывод данных.JPG (33.53 киб) просмотрено 276 раз

Indrekluuk
Чт 29 июня 2017 г. 10:53 утра
@RogerClark, у вас есть код где -то в GitHub? Если это так, как говорит @stevestrong, ILI9341 имеет тот же байт -заказ, то вопрос в.

Если вы используете «камеру».getPixelbyte (i) "или" камера.getPixelBuffer () "Тогда это должно быть в правильном порядке.

Indrekluuk
Чт 29 июня 2017 г. 14:40
С тех пор, как я делал камеру проект год назад, мне пришлось немного обновить память. (Я читаю свой код и комментарии).

Вот как я понимаю, что данные пикселя должны быть. Кажется, что спецификация не является на 100% правильной для этого.

1. Для разрешения VGA (без какой -либо понижения) байт -порядок с камеры
Low_0, high_0, low_1, high_1, ... Low_639, high_639
Мне пришлось поменять байты, чтобы получить правильные цвета

2. Для пониженного разрешения (QVGA и QQVGA) байт порядок переключается, а первое и последнее пиксель сломано.
(High_0 отсутствует), low_0, High_1, low_1, ... High_159, low_159, High_160 (<- Дополнительный половина пикселя)
Чтобы получить правильные цвета, я должен либо добавить дополнительный байт в начале (бросьте последнюю половину пикселя), либо в конце (бросьте кулак наполовину).


Если кто -то сможет доказать, что я ошибаюсь, я рад снова проверить это сам.

Стивестронг
Чт 29 июня 2017 г., 19:19
Мой проект чтения мощности с участием OV7670 с разрешением QQVGA отлично работает со всеми пикселями, но я признаю, что я использую только канал Y (GreyScale) 8 -битное значение.

Rogerclark
Чт 29 июня 2017 г. 22:01
[Indrekluuk - Чт 29 июня 2017 г. 10:53] - @RogerClark, у вас есть код где -то в GitHub? Если это так, как говорит @stevestrong, ILI9341 имеет тот же байт -заказ, то вопрос в.

Если вы используете «камеру».getPixelbyte (i) "или" камера.getPixelBuffer () "Тогда это должно быть в правильном порядке.
Мой код - взлом, но я застегну и отправлю его по электронной почте (как и я администратор, я могу найти ваш адрес электронной почты, на котором вы регистрируете)

Пса. Я не допускаю привязанности к PMS, поскольку он ест много дискового пространства, и есть другие проблемы с этим

Rogerclark
Пт 30 июня 2017 г. 3:38
Глядя на мой код, я не сильно изменился, так что вот что я сделал

Камера запускала QQVGA (я ничего не изменил)


В основном.CPP

Удалите материал о дисплее 7735 и добавьте код для дисплея ILI9341

#include "SPI.h" #include // Core graphics library, with extra fonts. #include // STM32 DMA Hardware-specific library #define TFT_CS PA2 #define TFT_DC PA0 #define TFT_RST PA1 Adafruit_ILI9341_STM tft = Adafruit_ILI9341_STM(TFT_CS, TFT_DC, TFT_RST); // Use hardware SPI

Indrekluuk
СЕД 1 июля 2017 г., 6:30
Это немного странно. Для меня кажется, что вам не нужно обмениваться байтом.

Я заказал это на eBay:
http: // www.eBay.com/itm/2-4-spi-tft-lcd ... 2749.L2649
Чтобы связаться со мной, требуется пару недель. Тогда я могу попробовать сам.

Не могли бы вы отправить весь проект? Затем я могу добавить поддержку ILI9341 в мой репо GitHub после того, как я заработаю.

Вы пробовали версию QVGA?

Стивестронг
Сб, 1 июля 2017 г. 8:52 утра
[Indrekluuk - Сб, 1 июля 2017 г. 6:30] - Я заказал это на eBay:
http: // www.eBay.com/itm/2-4-spi-tft-lcd ... 2749.L2649
Я заказал точно такую ​​же ЖК -дисплей с той же продавцом пару дней назад. Посмотрим, получим ли мы тот же контроллер борта :?

Rogerclark
SAT 1 июля 2017 г. 10:45 утра
[Indrekluuk - Сб, 1 июля 2017 г. 6:30] - Это немного странно. Для меня кажется, что вам не нужно обмениваться байтом.

Я заказал это на eBay:
http: // www.eBay.com/itm/2-4-spi-tft-lcd ... 2749.L2649
Чтобы связаться со мной, требуется пару недель. Тогда я могу попробовать сам.

Не могли бы вы отправить весь проект? Затем я могу добавить поддержку ILI9341 в мой репо GitHub после того, как я заработаю.

Вы пробовали версию QVGA?
Извини. У меня еще не было времени попробовать.

Концзакп
Солнце 2 июля 2017 г. 18:18
Кто -нибудь пытался использовать слот SD -карты с этой конфигурацией? Я хотел попытаться сохранить одну каркас изображения с камеры на SD -карте, но у меня проблемы. Я не могу инициализироваться SD:/ До сих пор у меня не было проблем с слотом SD -карты в других проектах, и я использовал библиотеку SD с кодом, как это:
#include #include File myFile; void setup() { SPI.setModule(1); Serial.begin(115200); delay(4000); Serial.print("Initializing SD card..."); if (!SD.begin(PA4)) { Serial.println("initialization failed!"); return; } Serial.println("initialization done."); if (SD.remove("programs.txt")) { Serial.println("Removing old file"); } else { Serial.println("Nothing to remove"); } // open the file. note that only one file can be open at a time, // so you have to close this one before opening another. myFile = SD.open("programs.txt", FILE_WRITE); // if the file opened okay, write to it: if (myFile) { Serial.print("Writing to file..."); myFile.println("testing 1, 2, 3."); // close the file: myFile.close(); Serial.println("done."); } else { // if the file didn't open, print an error: Serial.println("error opening file"); } // re-open the file for reading: myFile = SD.open("programs.txt"); if (myFile) { Serial.print("Opening file : "); // read from the file until there's nothing else in it: while (myFile.available()) { Serial.write(myFile.read()); } // close the file: myFile.close(); } else { // if the file didn't open, print an error: Serial.println("error opening file"); } } void loop() { // nothing happens after setup }

Пито
Солнце 2 июля 2017 г. 18:51
Я бы использовал SDFAT вместо этого.
PB3 и PB4 должны быть включены, в противном случае они используются для SWD/JTAG/DEBUG.
Почему SD.Начните с PA4?

Концзакп
Солнце 2 июля 2017 г., 19:14
Потому что я также пытался по умолчанию SS PIN -код на SPI1. Я также попробовал PA2 до высокого уровня перед инициализацией SD -карты. Без какого -либо успеха. Что вы имеете в виду, что я должен включить PB3 и PB4 ? как PinMode (PB4, выход)?

Пито
Солнце 2 июля 2017 г., 19:18
PB3,4 "Включение" disableDebugPorts();

Концзакп
Пн, 3 июля 2017 г., 16:32
К сожалению, это не помогло. Все еще инициализация не удалась. Кто -нибудь может попытаться получить SD -бег? Может, мое устройство сломано ....

Пито
Пн, 3 июля 2017 г., 17:00
Библиотека «SD» старая. Вместо этого используйте SDFAT, как я писал выше.

Концзакп
Пн, 3 июля 2017 г., 17:16
Я тоже попробовал это (пример чтения)

Стивестронг
Пн, 3 июля 2017 г., 17:59
@konczakp,
Извините, но я думаю, что ваша проблема не связана с этой темой (см. Название).
Не могли бы вы откройте еще одну ветку в другой группе потоков (например, здесь: http: // www.STM32duino.com/viewforum.PHP?f = 9)?
Спасибо.

Концзакп
Пн, 3 июля 2017 г. 18:23
Но я думаю, что это связано с предметом, потому что я хотел сохранить раму от OV7670 на SD -карте, которая установлена ​​на экране TFT. И это единственная тема, в которой создатель этой библиотеки принимает участие. И, по моему мнению, проблема с SD -картой связана с кодом и подключением к экрану. Для меня не понятно, почему экран с SPI использует разные булавки, чем нормальные выводы SPI (они свободны). Например, нормальный штифт MISO находится на PIN PA6, но для экрана использовался PA3. Та же ситуация с SS PIN. Я думаю, что это испортилось с слотом SD или, может быть, у меня не было рабочего устройства. Вот почему попросили кого -нибудь проверить. Более того, я думаю, что хранение кадра на SD является основной функцией, потому что отправка через UART будет медленной.

Пито
Пн, 3 июля 2017 г. 18:32
Также обращайте внимание на платы TFT с гнездом SDCARD, как правило, получают резисторы 1K-2K2 последовательно с SPI-сигналами (Shifter Man Shifter на уровне 5 В). Это может не работать надежно на скорости выше 8 МГц, поэтому при использовании с 3.3V сигналы (т.е. STM32) замените эти резисторы на 22-33oM. Для меня не понятно, почему экран с SPI использует разные булавки, чем нормальные выводы SPI (они свободны). Например, нормальный штифт MISO находится на PIN PA6, но для экрана использовался PA3. Та же ситуация с SS PIN. Я не понимаю твою проблему.. Вы можете подключить TFT к SPI1 и SDCARD с SPI2, или наоборот. Вы можете использовать любой PIN -код для CS CARD, а также для TFT CS вы можете использовать любой PIN -код, который вы хотите..
С MM/BP при использовании SPI1 только вы можете попробовать TFT CS - PA2 TFT MISO - PA6 - MISO SD TFT SCK - PA5 - SCK SD TFT MOSI - PA7 - MOSI SD - PA3 - CS SD

Стивестронг
Пн, 3 июля 2017 г., 19:31
ОК, так что проводка SCK, MISO и MOSI должно быть так, как упомянуто пито.

Для выводов CS вы можете выбрать любой из оставшихся, а также PA4 (я также использую его в своих проектах) или любой другой PA0..PA3.
Но не забудьте установить режим в качестве вывода для CS PINS! (Я не вижу этого в вашем коде...) pinMode(SD_CS, OUTPUT);

Концзакп
Пн, 3 июля 2017 г., 19:35
Хорошо, я попробую это

Пито
Пн, 3 июля 2017 г., 8:00 вечера
При тестировании сначала попробуйте TFT наедине с демо -версией, затем попробуйте SDCARD наедине с демо.
Опять же, при использовании отдельного SPI для обоих вы должны гарантировать, что ваш код не будет доступа к TFT и SDCARD в один и тот же момент (CS_CARD и CS_TFT не могут быть низкими в одно и то же время).

Концзакп
Пн, 3 июля 2017 г. 8:08 вечера
Я уже проверил это отдельно. У меня есть рабочий экран с камерой OV. При попытке только SD я не могу инициализировать его. Это что -то новое для меня, потому что у меня не было проблем с использованием слота SD -карты с 8 -битной параллельной ILI9341. :( Вот почему я подозреваю некоторые проблемы с оборудованием. Чтобы не достигать обоих (экран и SD) одновременно, я устанавливаю SS PIN -код экрана на высокий. Этого должно быть достаточно.

ZMEMW16
Пн, 3 июля 2017 г., 8:25 вечера
Это, вероятно, не сработает слишком хорошо, если оба находятся на одном выводе, также оба контакта понадобится набор для вывода.
SRP

Концзакп
Пн, 3 июля 2017 г. 20:29
Какой булавку вы имеете в виду?
TFT CS(SS) - PA2 TFT A0(MISO) - PA3 TFT SCK - PA5 - SCK SD - PA6 - MISO SD TFT SDA(MOSI) - PA7 - MOSI SD - PB3 - CS(SS) SD

ZMEMW16
Пн, 3 июля 2017 г., 8:34 вечера
Кажется, мои оптические чтения на одном уровне с чтением моей памяти, извините, я неправильно читал это.
PA2 & PB3 оба нуждаются в линии, чтобы установить их в виде выходов и изначально установить оба высоких.
Стивен

Пито
Пн, 3 июля 2017 г. 20:39
Как первый шаг отключите все, кроме проводов SDCARD, DoubleCheck.
Используйте SDFAT, например: #include "SPI.h" #include "SdFat.h" const uint8_t chipSelect = PA3; SdFat sd; SdFile file; void setup() { delay(3000); Serial.begin(115200); if (!sd.begin(chipSelect, SD_SCK_MHZ(18))) { Serial.println("INIT ERROR"); sd.initErrorHalt(); // prints out sdfat's error codes } else { Serial.println("INIT OK"); } delay(500); } void loop() { }

ZMEMW16
Пн, 3 июля 2017 г. 20:47
Это хитрый переводчик : D
Я только что удалил свой пост о тебе, означающем PB3, а не PA3, btdtgt : D
Стивен

Концзакп
Ср. 05 июля 2017 г. 18:27
Я перешел на ILI9341, потому что я не мог получить оба, экран и SD -карту, работая на меньшем экране. Они работали отдельно, но при попытке объединить их вместе работали только экран. Экран не реагировал на SS PIN -конец как -то. Теперь на ILI9341 я могу читать SD -карту и предварительный просмотр изображения с камеры на экране, поэтому изменения, сделанные Rogerclark. Но это работает только тогда, когда я читаю SD перед отправкой initliveov7670 (); Если я попытаюсь прочитать SD -карту после initliveov7670 (), то программа висит. Если я пытаюсь прочитать SD в Main Loop () после Praceframe (), я получаю беспорядок на экране. Я не понимаю, почему? Я думал, что могу прочитать 1 кадр, а затем прочитать SD и так далее. Обычно я хочу показать все на экране, но когда наступит прерывание, я хочу заморозить экран и хранить 1 изображение (кадр) на SD, а после этого начнутся отправлять на экран. Любые советы по этому поводу ?

Пито
Ср. 05 июля 2017 г. 18:47
Давно обсуждалась проблема - SDCards не выпускают мисо (не помещайте ее в Highz), когда CS CS выходит высоко.
Обходной путь состоит в том, чтобы выпустить фиктивную 8 -битную транзакцию SPI после того, как CS выходит на высокую часть (после того, как SDCARD отменит).
При повеселе SDCARD и TFT на том же автобусе SPI это может вызвать проблему.
Но я думаю, что это уже было исправлено, по крайней мере, в SDFAT уже..

Стивестронг
Ср. 5 июля 2017 г., 19:22
Если я не ошибаюсь, initliveov7670 () отключает прерывания, поэтому любые функции задержки или миллисы с использованием Systick будут висеть.
И это не хорошо для SDFAT...

Indrekluuk
Чт, 6 июля 2017 г. 6:09
Да, я отключаю прерывания, так как он сломает чтение линии.

Вы могли бы удалить "noEversrupts ();" Из метода init и отключить их только временно во время чтения строки:
noEverseRrupts ();
камера.readline ();
прерывания ();

Концзакп
Пт, 07 июля 2017 г., 19:24
ОК, я изменил: https: // github.com/indrekluuk/liveov767 ... Леуарт.CPP
Теперь мой главный.CPP выглядит как:
#include "main.h" #include "Arduino.h" #include "src/camera/buffered/BufferedCameraOV7670.h" #include "src/camera/buffered/stm32_72mhz/BufferedCameraOV7670_QQVGA_30hz.h" #include "src/camera/buffered/stm32_72mhz/BufferedCameraOV7670_QQVGA.h" #include // STM32 DMA Hardware-specific library #include File myFile; #define TFT_CS PA2 #define TFT_DC PA0 #define TFT_RST PA1 BufferedCameraOV7670_QQVGA camera(CameraOV7670::PIXEL_RGB565, BufferedCameraOV7670_QQVGA::FPS_15_Hz); //BufferedCameraOV7670_QQVGA_30hz camera(CameraOV7670::PIXEL_RGB565); //BufferedCameraOV7670 camera( // CameraOV7670::RESOLUTION_QQVGA_160x120, // CameraOV7670::PIXEL_RGB565, // 4); Adafruit_ILI9341_STM tft = Adafruit_ILI9341_STM(TFT_CS, TFT_DC, TFT_RST); // Use hardware SPI void initLiveOV7670() { // Serial.begin(); pinMode(PC13,OUTPUT);// flashing frame LED pinMode(PB10, INPUT); tft.begin(); tft.setRotation(3); bool cameraInitialized = camera.init(); if (cameraInitialized) { tft.fillScreen(ILI9341_BLACK); } else { tft.fillScreen(ILI9341_RED); while(1); } // noInterrupts(); } inline void sendLineToDisplay() __attribute__((always_inline)); //inline void screenLineStart(void) __attribute__((always_inline)); //inline void screenLineEnd(void) __attribute__((always_inline)); inline void sendPixelByte(uint8_t byte) __attribute__((always_inline)); inline void pixelSendingDelay() __attribute__((always_inline)); //static const uint16_t lineLength = 320; //static const uint16_t lineCount = 240; // Normally it is a portrait screen. Use it as landscape //uint8_t screen_w = 320; uint8_t screen_h = 240; uint8_t screenLineIndex; // this is called in Arduino loop() function void processFrame() { screenLineIndex = screen_h; digitalWrite(PC13,!digitalRead(PC13)); String strser = ""; while (Serial.available () > 0) { strser += char(Serial.read ()); } if (strser != ""){ if (strser.startsWith("test")){ // Wyślij pakiet testowy przez nrf24l01 oraz zrób test karty sd tft.fillScreen(ILI9341_WHITE); pinMode(PA2, OUTPUT); pinMode(PB3, OUTPUT); digitalWrite(PA2, HIGH); digitalWrite(PB3, LOW); frame_sd(); digitalWrite(PA2, LOW); digitalWrite(PB3, HIGH); tft.begin(); tft.setRotation(3); tft.fillScreen(ILI9341_WHITE); } } camera.waitForVsync(); noInterrupts(); for (uint8_t i = 0; i < camera.getLineCount(); i++) { camera.readLine(); sendLineToDisplay(); } interrupts(); } uint8_t dispBuf[320*2]; uint8_t b1; uint8_t *tdBufEnd = dispBuf + 320*2; void sendLineToDisplay() { uint8_t *cBufPtr = (uint8_t *)camera.getPixelBuffer(); uint8_t *tdBuf = dispBuf; // pixel duplicate and byte swap while(tdBuf < tdBufEnd) { b1=*cBufPtr++; *tdBuf++=*cBufPtr; *tdBuf++=b1; *tdBuf++=*cBufPtr++; *tdBuf++=b1; } //send the same line twice // Note. SPI.dmaSendAsync() is also OK and probably better, but I went back to the blocking version last time I was testing things SPI.dmaSend((uint8_t *)dispBuf,camera.getPixelBufferLength()); SPI.dmaSend((uint8_t *)dispBuf,camera.getPixelBufferLength()); } void init_sd(void){ SPI.setModule(1); Serial.print("Initializing SD card..."); if (!SD.begin(PB3)) { Serial.println("initialization failed!"); return; } Serial.println("initialization done."); } void check_sd(void){ if (SD.remove("programs.txt")) { Serial.println("Removing old file"); } else { Serial.println("Nothing to remove"); } // open the file. note that only one file can be open at a time, // so you have to close this one before opening another. myFile = SD.open("programs.txt", FILE_WRITE); // if the file opened okay, write to it: if (myFile) { Serial.print("Writing to file..."); myFile.println("testing 1, 2, 3."); // close the file: myFile.close(); Serial.println("done."); } else { // if the file didn't open, print an error: Serial.println("error opening file"); } // re-open the file for reading: myFile = SD.open("programs.txt"); if (myFile) { Serial.print("Opening file : "); // read from the file until there's nothing else in it: while (myFile.available()) { Serial.write(myFile.read()); } // close the file: myFile.close(); } else { // if the file didn't open, print an error: Serial.println("error opening file"); } } CameraOV7670::PixelFormat pixelFormat = CameraOV7670::PIXEL_RGB565; inline void endOfFrame_sd(void) __attribute__((always_inline)); inline void endOfLine_sd(void) __attribute__((always_inline)); inline void sendNextPixelByte_sd() __attribute__((always_inline)); inline void sendPixelByteH_sd(uint8_t byte) __attribute__((always_inline)); inline void sendPixelByteL_sd(uint8_t byte) __attribute__((always_inline)); static const uint16_t lineLength = 160; static const uint16_t lineCount = 120; uint8_t lineBuffer [lineLength*2 + 1 + 5]; uint16_t lineBufferIndex = 0; void frame_sd(void){ SD.remove("frame"); myFile = SD.open("frame", FILE_WRITE); if (myFile) { camera.waitForVsync(); for (uint16_t y = 0; y < lineCount; y++) { lineBufferIndex = 0; lineBuffer[0] = 0; // first byte from Camera is half a pixel for (uint16_t x = 1; x < lineLength*2+1; x+=5) { // start sending first bytes while reading pixels from camera sendNextPixelByte_sd(); // we can read 5 bytes from camera while one byte is sent over UART camera.waitForPixelClockRisingEdge(); lineBuffer[x] = camera.readPixelByte(); camera.waitForPixelClockRisingEdge(); lineBuffer[x+1] = camera.readPixelByte(); camera.waitForPixelClockRisingEdge(); lineBuffer[x+2] = camera.readPixelByte(); camera.waitForPixelClockRisingEdge(); lineBuffer[x+3] = camera.readPixelByte(); camera.waitForPixelClockRisingEdge(); lineBuffer[x+4] = camera.readPixelByte(); } // send rest of the line while (lineBufferIndex < lineLength * 2) { sendNextPixelByte_sd(); } endOfLine_sd(); } endOfFrame_sd(); myFile.close(); } } void sendNextPixelByte_sd() { uint8_t byte = lineBuffer[lineBufferIndex]; uint8_t isLowPixelByte = lineBufferIndex & 0x01; // make pixel color always slightly above 0 since zero is end of line if (isLowPixelByte) { sendPixelByteL_sd(byte); } else { sendPixelByteH_sd(byte); } lineBufferIndex++; } void sendPixelByteH_sd(uint8_t byte) { // RRRRRGGG myFile.print(byte | 0b00001000); } void sendPixelByteL_sd(uint8_t byte) { // GGGBBBBB myFile.print(byte | 0b00100001); } void endOfFrame_sd() { // frame width myFile.print((lineLength >> 8) & 0xFF); myFile.print(lineLength & 0xFF); // frame height myFile.print((lineCount >> 8) & 0xFF); myFile.print(lineCount & 0xFF); // pixel format myFile.print((pixelFormat)); myFile.print(0xFF); myFile.print(0x00); myFile.print(0x00); myFile.print(0x00); } void endOfLine_sd() { myFile.print(0x00); } void sendPixelByte(uint8_t byte) { spi_tx_reg(SPI1, byte); //SPI.transfer(byte); // this must be adjusted if sending loop has more/less instructions asm volatile("nop"); asm volatile("nop"); asm volatile("nop"); asm volatile("nop"); asm volatile("nop"); asm volatile("nop"); asm volatile("nop"); asm volatile("nop"); asm volatile("nop"); } void pixelSendingDelay() { asm volatile("nop"); asm volatile("nop"); asm volatile("nop"); asm volatile("nop"); asm volatile("nop"); asm volatile("nop"); asm volatile("nop"); asm volatile("nop"); asm volatile("nop"); asm volatile("nop"); asm volatile("nop"); asm volatile("nop"); asm volatile("nop"); asm volatile("nop"); asm volatile("nop"); asm volatile("nop"); asm volatile("nop"); asm volatile("nop"); }

Концзакп
Солнце 9 июля 2017 г. 8:36 утра
Я изменил каждую печать на файл SD с
myFile.print(byte | 0b00001000);

Пито
Солнце 9 июля 2017 г. 8:45 утра
Если вам нужно бинарное использование myFile.write(byte);

Концзакп
Солнце 9 июля 2017 г. 12:02
На этом этапе я не могу использовать библиотеку SDFAT, потому что для работы экрана мне пришлось скачать модифицированную библиотеку SPI, с которой SDFAT не работает, но SD Lib работает нормально, поэтому мне нужно придерживаться этого, или кто -то получил Spi Lib, работающий с оба?

Я пытался написать функцию, но это дает мне точно такой же результат, поэтому проблема где -то еще.

Zoomx
Солнце 9 июля 2017 г. 15:37
Наклонные линии обычно указывают на то, что в выравнивании пикселей есть ошибка, возможно, вам нужно переключить 160 с 120.

Насколько я знаю, необработанные изображения OV7660 не являются значениями RGB, потому что есть фильтр Bayer, и поэтому цвета упакованы по -разному.
Изображение
Код, используемый Computernerd, использует конвертер.
https: // github.com/computernerd/rawcame ... -конвертер

Концзакп
Солнце 9 июля 2017 г., 16:32
С компьютернером я получаю это:
кадр 1.png
кадр 1.PNG (111.09 киб) просмотрено 355 раз

Пито
Солнце 9 июля 2017 г., 17:47
Используйте зеленый свет/зеленый сцену и сделайте выстрел, затем синий, затем красный - вы получите 3 файла, и вы можете сравнить - организация RGB внутри файла будет легко видна :ржу не могу:

Концзакп
Солнце 9 июля 2017 г. 18:42
Очень хорошая идея, потому что она показала не только цвета, но и то, что беспокоит меня больше, что экран умножается и немного повернут (не прямо) :( :? И я понятия не имею, почему :?: . Я взял код из примера Indrekluuk UART и изменился только для того, чтобы отправить данные не в UART, а на SD -карту. Есть какая -то неправильная синхронизация или что ?

Красный:
R.Jpg
Ведущий.JPG (8.24 киб) просмотрено 346 раз

ZMEMW16
Солнце 9 июля 2017 г., 19:08
Не могли бы вы вызвать все 3 с той же «точки», то есть зеленый по сравнению с красным и синим по сравнению с красным
Как кажется, каждая линия движется вправо, может быть, длина линии слишком длинная
Оба являются глупыми идеями, конечно
Стивен

Концзакп
Солнце 09 июля 2017 г. 8:19 вечера
Я не знаю, понял ли я тебя правильно ... Ты имеешь в виду это -> https: // загрузить.Викимедия.орг/Википедия/ ... аг.Svg.пнн Если да, то это кадр:
Буфер обширного обхода02.jpg
Буфер обмена02.JPG (8.01 киб) просмотрено 344 раза

Пито
Солнце 9 июля 2017 г. 22:02
Я точно не знаю, как/когда вы пишете на SDCARD - помните о задержке записи SDCARD может составлять 5-150 мс в любое время, поэтому, если вы делаете это в синхронизации с захватом видео, это может быть проблемой (нет такой проблемы При отправке через UART).. Вы должны использовать Buffer FIFO, чтобы покрыть отключения писать SDCARD, тогда..
Кроме того, я не понимаю, как вы можете прочитать приведенные выше данные из файла SDCARD, когда вы пишете их как двоичный. Это не бинарный.. 1189173140109771091401652004924571714157491421671069910616720712510810775431071072002252410110

Концзакп
Пн 10 июля 2017 г. 6:54
Это код, ответственный за чтение с камеры и отправку данных на SD -карту
CameraOV7670::PixelFormat pixelFormat = CameraOV7670::PIXEL_RGB565; inline void endOfFrame_sd(void) __attribute__((always_inline)); inline void endOfLine_sd(void) __attribute__((always_inline)); inline void sendNextPixelByte_sd() __attribute__((always_inline)); inline void sendPixelByteH_sd(uint8_t byte) __attribute__((always_inline)); inline void sendPixelByteL_sd(uint8_t byte) __attribute__((always_inline)); static const uint16_t lineLength = 160; static const uint16_t lineCount = 120; uint8_t lineBuffer [lineLength*2 + 1 + 5]; uint16_t lineBufferIndex = 0; void frame_sd(void){ SD.remove("frame"); myFile = SD.open("frame", FILE_WRITE); if (myFile) { camera.waitForVsync(); for (uint16_t y = 0; y < lineCount; y++) { lineBufferIndex = 0; lineBuffer[0] = 0; // first byte from Camera is half a pixel for (uint16_t x = 1; x < lineLength*2+1; x+=5) { // start sending first bytes while reading pixels from camera sendNextPixelByte_sd(); // we can read 5 bytes from camera while one byte is sent over UART camera.waitForPixelClockRisingEdge(); lineBuffer[x] = camera.readPixelByte(); camera.waitForPixelClockRisingEdge(); lineBuffer[x+1] = camera.readPixelByte(); camera.waitForPixelClockRisingEdge(); lineBuffer[x+2] = camera.readPixelByte(); camera.waitForPixelClockRisingEdge(); lineBuffer[x+3] = camera.readPixelByte(); camera.waitForPixelClockRisingEdge(); lineBuffer[x+4] = camera.readPixelByte(); } // send rest of the line while (lineBufferIndex < lineLength * 2) { sendNextPixelByte_sd(); } endOfLine_sd(); } endOfFrame_sd(); myFile.close(); } } void sendNextPixelByte_sd() { uint8_t byte = lineBuffer[lineBufferIndex]; uint8_t isLowPixelByte = lineBufferIndex & 0x01; // make pixel color always slightly above 0 since zero is end of line if (isLowPixelByte) { sendPixelByteL_sd(byte); } else { sendPixelByteH_sd(byte); } lineBufferIndex++; } void sendPixelByteH_sd(uint8_t byte) { // RRRRRGGG myFile.print(byte | 0b00001000); } void sendPixelByteL_sd(uint8_t byte) { // GGGBBBBB myFile.print(byte | 0b00100001); } void endOfFrame_sd() { // frame width myFile.print((lineLength >> 8) & 0xFF); myFile.print(lineLength & 0xFF); // frame height myFile.print((lineCount >> 8) & 0xFF); myFile.print(lineCount & 0xFF); // pixel format myFile.print((pixelFormat)); myFile.print(0xFF); myFile.print(0x00); myFile.print(0x00); myFile.print(0x00); } void endOfLine_sd() { myFile.print(0x00); }

Стивестронг
Пн 10 июля 2017 г. 9:27 утра
Почему бы вам не использовать мульти-байтовые записи? Это должно быть быстрее, чем одинокий байт пишет.
Подготовьте данные в буфере, а затем используйте myFile.write(buf, nr_bytes);

ZMEMW16
Пн 10 июля 2017 г. 10:43
@konczakp
Эта линия на изображении для меня говорит, что длина линии короткая, она должна быть вертикальной ??

Тогда у вас будет три вертикальные полосы, найдите начало каждой группы и из начальных точек
Возможно объединить три значения в «что -то», пиксель, цветовой код и т. Д

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

Стивен

Indrekluuk
Вт 11 июля 2017 г. 11:57 утра
Насколько велик двоичный файл?
Это должно быть ровно 120*160*2 = 38400 байтов (2 байта на пиксель в формате RGB565)

Возможно, есть также проблемы с времени. Если myfile.Печать блокирует, тогда вы, вероятно, пропустите пиксели.
В примере UART отправка данных через UART не блокировала. Пока я отправлял один байт по UART, я читал следующие 5 байтов от камеры.

Может быть, было бы лучше использовать буферизованную версию (не пример UART, который читает один пиксель в то время). Затем после прочтения линии с камеры вы можете написать линию с каким -то буферизованным методом записи на SD -карту.

Когда я получаю дисплей ILI9341, я также могу попробовать его сам также. Я могу измерить с осциллографом, если есть достаточно времени, чтобы записать данные на SD -карту.

Концзакп
Вт 11 июля 2017 г. 12:07
Это имеет смысл! :) Но я не знаю, как писать в SD, не блокируя чтение камеры:/
Может, вы могли бы попробовать это с меньшим экраном. Эта проблема не зависит от оборудования, потому что на меньшем экране также есть слот SD. Вы можете подключить только SD (без экрана) и попытаться запустить этот код один раз в функции настройки или в цикле и перезаписать файл.
Мой файл составляет около 100 кб, если я помню правильно, потому что я сейчас на работе.

Пито
Вторник 11 июля 2017 г. 13:48
Но я не знаю, как писать в SD, не блокируя чтение камеры:/ Это было бы сложно, так как у SDCards есть задержки записи (см. Выше мой пост).
Написание файла 38 КБ на SDCARD может длиться от 20 мс.
Лучший способ продолжить - это изменить доску для F103 с 64 -километровым оперативным операцией или F407 и сохранить видео кадров 38 КБ в буфере.
Или, чтобы сохранить изображение в небольших кусках, такой буфер вписывается в ваш F103, а затем собирайте файлы на вашем ПК.
Или используйте Freertos и используйте FIFO для написания на SDCARD (продюсер будет задачей, считывающим байты с модуля камеры в FIFO, и потребитель будет задачей, написавшим байты с FIFO на SDCARD)..

Indrekluuk
Сб 15 июля 2017 г. 7:59 утра
Если написание данных на SD -карту занимает миллисекунды, то невозможно хранить подобное изображение на лету. У вас должна быть какая -то память, вы храните изображение перед тем, как сохранить его на SD -карту

Rogerclark
Сб 15 июля 2017 г. 9:06 вечера
Одно простое решение памяти для хранения изображения - просто использовать дисплей.

Запишите данные данных на дисплей в режиме реального времени, затем прочитайте их строку за раз и отправляйте строку в SD.

Rogerclark
Sun 16 июля 2017 г., 7:41
КСТАТИ.

Может ли кто -нибудь опубликовать ссылку на версию QVGA или https: // github.com/indrekluuk/liveov7670 Теперь по умолчанию в QVGA
Или, возможно, мне нужно что -то изменить в последней версии от GitHub

Indrekluuk
Солнце 16 июля 2017 г. 8:24
Здесь:
https: // github.com/indrekluuk/liveov767 ... 2/Main.CPP


Комментарий из строки 35:
BufferedCameraov7670_qqvga Camera (CameraV7670 :: Pixel_rgb565, BufferedCameraov7670_qqvga :: fps_12_hz);


Удалить комментарии из строки 36:
BufferedCameraov7670_Qvga Camera (CameraV7670 :: Pixel_rgb565, BufferedCameraov7670_Qvga :: fps_7p5_hz);

Rogerclark
Солнце 16 июля 2017 г. 10:15 утра
Ах.

ХОРОШО.

Это в основном то, что я пытался сделать сам, но я не могу вспомнить, сработало ли это для меня, когда я снизил частоту кадров.

Я знаю, что он не работает со скоростью 12 кадров в секунду, так как экран недостаточно быстрый, чтобы принять QVGA на 12 кадров в секунду

Rogerclark
Пн 24 июля 2017 г. 22:23
Интересная тема об оптимизациях

http: // www.STM32duino.com/viewtopic.PHP ... 886#P31867


Возможно, мы сможем добавить эту прагму в файлы, которые нуждаются в оптимизации -O2, чтобы она работала OK без изменения платформы.текст

Концзакп
Пт 28 июля 2017 г. 13:26
[Rogerclark - Сб 15 июля 2017 г. 9:06 вечера] - Одно простое решение памяти для хранения изображения - просто использовать дисплей.

Запишите данные данных на дисплей в режиме реального времени, затем прочитайте их строку за раз и отправляйте строку в SD.
Это очень хорошая идея! Спасибо. Я искал интернет и нашел несколько примеров, и теперь я пытаюсь заставить его работать на STM32, но без какого -либо успеха. Он замерзает, когда я пытаюсь прочитать пиксель. (Я думал о чтении Pixel от Pixel, когда я получил все изображение от TFT Gram) Вот что я сделал.

В adafruit_ili9341_stm.H я добавил //Pio *_dcport; volatile uint8_t *_dcport, *_csport; uint8_t _cspinmask, _dcpinmask; SPISettings _spiSettings; uint8_t readdata(void), readcommand8(uint8_t reg, uint8_t index = 0); // Enables CS inline __attribute__((always_inline)) void enableCS(){ *_csport &= ~_cspinmask; } // Disables CS inline __attribute__((always_inline)) void disableCS() { *_csport |= _cspinmask; } __attribute__((always_inline)) void spiwrite16(uint16_t d) { SPI.transfer(highByte(d)); SPI.transfer(lowByte(d)); } // Writes commands to set the GRAM area where data/pixels will be written void setAddr_cont(uint16_t x, uint16_t y, uint16_t w, uint16_t h) __attribute__((always_inline)) { writecommand_cont(ILI9341_CASET); // Column addr set setDCForData(); write16_cont(x); // XSTART write16_cont(x+w-1); // XEND writecommand_cont(ILI9341_PASET); // Row addr set setDCForData(); write16_cont(y); // YSTART write16_cont(y+h-1); // YEND } // Sets DC to Data (1) inline __attribute__((always_inline)) void setDCForData() { *_dcport |= _dcpinmask; } // Sets DC to Command (0) inline __attribute__((always_inline)) void setDCForCommand(){ *_dcport &= ~_dcpinmask; } // Enables CS, sets DC for Command, writes 1 byte // Does not disable CS inline __attribute__((always_inline)) void writecommand_cont(uint8_t c) { setDCForCommand(); enableCS(); write8_cont(c); } // Enables CS, sets DC for Data and reads 1 byte // Does not disable CS __attribute__((always_inline)) uint8_t readdata8_cont() { setDCForData(); enableCS(); return read8_cont(); } // Reads 1 byte __attribute__((always_inline)) uint8_t read8_cont() { return SPI.transfer(ILI9341_NOP); } __attribute__((always_inline)) uint8_t read8_last() { uint8_t r = SPI.transfer(ILI9341_NOP); disableCS(); return r; } // Writes 2 bytes // CS, DC have to be set prior to calling this method __attribute__((always_inline)) void write16_cont(uint16_t d) { spiwrite16(d); } // writes 1 byte // CS and DC have to be set prior to calling this method __attribute__((always_inline)) void write8_cont(uint8_t c){ spiwrite(c); } __attribute__((always_inline)) void beginTransaction() { SPI.beginTransaction(_spiSettings); } __attribute__((always_inline)) void endTransaction() { SPI.endTransaction(); }

Стивестронг
Пт 28 июля 2017 г. 13:46
Где именно висит? После чего команда?

Rogerclark
Солнце 30 июля 2017 г. 7:10 утра
Ребята

К вашему сведению.

Я добавил модифицированную версию меню оптимизации @Mtiutiu в ядро ​​F1.

Это означает, что вам не нужно изменять свою платформу.TXT, чтобы сделать @ Indrekluuk's LiveOV7670 Code Run, так как вы можете выбрать оптимацию -O2 из меню

На самом деле я обнаружил, что LiveOV7670 работает нормально с оптимизацией -O1 или -O2 или -O3. Единственная оптимизация, с которой он не работает, -это наш текущий дефолт -OS (небольшой размер кода)

Концзакп
Пн 31 июля 2017 г., 7:21
он держится
// Sets DC to Command (0) inline __attribute__((always_inline)) void setDCForCommand(){ *_dcport &= ~_dcpinmask; }

Стивестронг
Пн 31 июля 2017 г. 8:23 утра
//Pio *_dcport; volatile uint8_t *_dcport, *_csport; uint8_t _cspinmask, _dcpinmask;

Концзакп
Пн 31 июля 2017 г. 8:34
Я изменился, как вы описали, но проблема остается в той же точке. :(

Стивестронг
Пн 31 июля 2017 г. 8:41
Какие булавки вы определили для DC? Проверьте маску тоже.

Концзакп
Пн 31 июля 2017 г. 9:11
Это мой булавка def
#define TFT_CS PA2 #define TFT_DC PA0 #define TFT_RST PA1

Стивестронг
Пн 31 июля 2017 г. 9:22
Маска постоянного тока неверна, если она показывает 0, это должно быть (1<<0), который 0x0001.
Попробуйте кодировать это как это значение исправления 0x0001.

Концзакп
Пн 31 июля 2017 г. 9:29
Не повезло ...

Изменить это на
inline __attribute__((always_inline)) void setDCForCommand(){ Serial.println("ok1"); *_dcport = 0x0001; Serial.println("ok2"); }

Rogerclark
Пн 31 июля 2017 г. 9:57 утра
Почему вы добавляете VAR и т. Д. Для портов ?

Библиотека уже имеет VARS для портов и использует их без каких -либо проблем E.глин.
void Adafruit_ILI9341_STM::writecommand(uint8_t c) { *dcport &= ~dcpinmask; *csport &= ~cspinmask; spiwrite(c); *csport |= cspinmask; }

Rogerclark
Пн 31 июля 2017 г. 9:59 утра
КСТАТИ.

Вы используете этот код в качестве примера ?

https: // форум.Микро.com/viewtopic.PHP? ... 39#P255898

Концзакп
Пн 31 июля 2017 г. 10:32 утра
нет. Я нашел его в какой -то библиотеке для ILI9341, но не мог работать целую либера.

Rogerclark
Пн 31 июля 2017 г. 10:47 утра
[Концзакп - Пн 31 июля 2017 г. 10:32] - нет. Я нашел его в какой -то библиотеке для ILI9341, но не мог работать целую либера.
Ах..

Это много объясняет.

Версия STM32 библиотеки Adafruit имеет много изменений от версии AVR, поэтому вы не можете просто вырезать и вставить код из версии AVR в версию STM32.

Я бы порекомендовал вам написать новую функцию, которую вы сами, так как она не выглядит такой сложной.

Возможно, основать его на ADAFRIT_ILI9341_STM :: Drawpixel функциональности в версии LIB STM32.

Вам также нужно скопировать
void adafruit_ili9341_stm :: setaddrwindow (uint16_t x0, uint16_t y0, uint16_t x1,
uint16_t y1)

Так что сделайте новую функцию, которая устанавливает пиксель для чтения.

Но это было бы очень похоже на SetAddrwindow,

Rogerclark
Пн 31 июля 2017 г. 10:50 утра
КСТАТИ.

Это задокументировано в

https: // cdn-shop.Адафрут.com/dataheets/ili9341.PDF

На странице 116, озаглавленная 8.2.24. Читая память (2EH)

Редактировать.

Обратите внимание на
Если контроль доступа к памяти B5 = 0: и
Если контроль доступа к памяти B5 = 1: который, кажется, контролирует, если пиксели считываются последовательно вдоль каждой строки / строки или вниз по каждому столбцу

Концзакп
Пн 31 июля 2017 г. 12:30
Я видел этот документ, но я также читал в Интернете, что есть какая -то проблема с этим автоматическим приращением. Кроме того, у каждой из которых я видел только PixelRead, поэтому я решил начать с Pixel Read. Если я не смогу читать целый грамм, я могу циклу через каждый пиксель. Я сделал 2 простой функции, как это:

1. uint16_t Adafruit_ILI9341_STM::readPixel(int16_t x, int16_t y) { beginTransaction(); //setAddr_cont(x, y, x + 1, y + 1); ? should it not be x,y,x,y? //setAddr_cont(x, y, 1, 1); writecommand(0x2A); // Column addr set spiwrite16(x); // XSTART spiwrite16(x); // XEND writecommand(0x2B); // Row addr set spiwrite16(y); // YSTART spiwrite16(y); // YEND writecommand(0x2E); // read from GRAM SPI.transfer(ILI9341_NOP); // dummy read uint8_t red = SPI.transfer(ILI9341_NOP); uint8_t green = SPI.transfer(ILI9341_NOP); uint8_t blue = SPI.transfer(ILI9341_NOP); uint16_t color = color565(red, green, blue); endTransaction(); return color; }

Стивестронг
Пн 31 июля 2017 г. 12:45
Имейте в виду, что фактический adafruit_ili9341_stm lib обычно использует 16 -битные передачи SPI.

Так что обработайте данные о считывании пикселей как 16 -битные данные.

Или, прежде чем вы захотите прочитать пиксели обратно в 8 битмоде, сначала необходимо установить режим SPI на 8 бит, используя эту линию: if (hwSPI) SPI.setDataSize(0);

Rogerclark
Пн 31 июля 2017 г., 21:32
Я не вижу смысла в выполнении 8 -битных переводов для этого, так как пиксели 16 -битные.

Стивестронг
Вторник 01 августа 2017 г. 9:42
Просто для записи, я публикую здесь эту ссылку, я нашел ее после этого, я начал реализовать похожую, но гораздо более простую версию (вообще не прерывается).
http: // qyx.Krtko.org/projects/ov2640_stm32/
Интересная часть этого заключается в том, что он, очевидно, читает из регистра IDR в 8 -битном режиме с использованием DMA, мне интересно, действительно ли это работает, в справочном руководстве написано, что эти регистры должны быть доступны в виде слов (32 -битный режим).

Rogerclark
Вторник 01 августа 2017 г. 10:11
Стив

Это очень интересно.

Где это настроено, чтобы сделать 8 -битные чтения ?
Я вижу эту функцию все
dmaStreamSetPeripheral(dmastp, (uint8_t *)(&(GPIOE->IDR)) + 1);

Стивестронг
Вторник 01 августа 2017 г. 11:25
Да, это настройка периферийного адреса DMA. И в 32 -битном режиме должен быть выровнен по 4 байтовому адресу, что, очевидно, здесь не так.
Он читает верхние 8 битов (7..15) порта GPIOE:
https: // github.com/iqyx/ov2640-stm32/bl ... айн.C#1856
И я также намерен использовать GPIOB 7..15.

Я только что понял, что это работает на дискотеке F4 (что не было ясно из блога).
Итак, в этом случае (для F4) 8 -битное чтение IDR, вероятно, работает.
Если это не сработает, необходимо будет необходимо некоторые дополнительные вещи (повторное заказа).

РЕДАКТИРОВАТЬ
Справочное руководство F4 также не подтверждает этот трюк (см. RM0090, глава. 8.4.5): Bits 15:0 IDRy: Port input data (y = 0..15) These bits are read-only and can be accessed in word mode only. They contain the input value of the corresponding I/O port.

Rogerclark
Вторник 01 августа 2017 г. 11:50 утра
Возможно, это недокументированная особенность

Надеемся, что если он сработает на F1, он будет работать на F1

Концзакп
Вторник 01 августа 2017 13:26
Я попробовал все советы и также сравнил все с библиотекой TFT и в конечном итоге получил пошаговую процедуру для чтения грамма, но он все еще не работает. Я также пытался использовать нормальные функции из LIB. Я не понимаю, почему и что не так. КСТАТИ. Перед вызовом этой функции я заполняю экран красным цветом. Это мой последний код:
uint16_t Adafruit_ILI9341_STM::readPixel_simple(int16_t x, int16_t y) { *dcport &= ~dcpinmask; // writecommand(uint8_t c) *csport &= ~cspinmask; // writecommand(uint8_t c) spiwrite(ILI9341_CASET); // writecommand(uint8_t c) *csport |= cspinmask; // writecommand(uint8_t c) *dcport |= dcpinmask; *csport &= ~cspinmask; SPI.write(x); SPI.write(x+1); // maybe only x *dcport &= ~dcpinmask; // writecommand(uint8_t c) *csport &= ~cspinmask; // writecommand(uint8_t c) spiwrite(ILI9341_PASET); // writecommand(uint8_t c) *csport |= cspinmask; // writecommand(uint8_t c) *dcport |= dcpinmask; *csport &= ~cspinmask; SPI.write(y); SPI.write(y+1); // maybe only x *dcport &= ~dcpinmask; // writecommand(uint8_t c) *csport &= ~cspinmask; // writecommand(uint8_t c) spiwrite(ILI9341_RAMWR); // writecommand(uint8_t c) *csport |= cspinmask; // writecommand(uint8_t c) *dcport &= ~dcpinmask; // writecommand(uint8_t c) *csport &= ~cspinmask; // writecommand(uint8_t c) spiwrite(ILI9341_RAMRD); // writecommand(uint8_t c) *csport |= cspinmask; // writecommand(uint8_t c) *dcport |= dcpinmask; *csport &= ~cspinmask; SPI.transfer(0x00); // dummy read *csport |= cspinmask; *dcport |= dcpinmask; *csport &= ~cspinmask; Serial.print(SPI.transfer(0x00)); // RED read *csport |= cspinmask; *dcport |= dcpinmask; *csport &= ~cspinmask; Serial.print(SPI.transfer(0x00)); // GREEN read *csport |= cspinmask; *dcport |= dcpinmask; *csport &= ~cspinmask; Serial.println(SPI.transfer(0x00)); // BLUE read *csport |= cspinmask; }

Стивестронг
Вторник 01 августа 2017 г., 14:20
Вам не нужно переключать CS и DC между последовательными чтениями данных (SPI.переводы...) ... spiwrite(ILI9341_RAMRD); // writecommand(uint8_t c) *dcport |= dcpinmask; SPI.transfer(0x00); // dummy read ------------------- will read 16 bits ! Serial.print(SPI.transfer(0x00)); // RED read------------------- will read 16 bits ! Serial.print(SPI.transfer(0x00)); // GREEN read------------------- will read 16 bits ! Serial.println(SPI.transfer(0x00)); // BLUE read------------------- will read 16 bits ! *csport |= cspinmask;

Стивестронг
Ср. 02 августа 2017 12:00
Вернуться к корням.

Кажется, что хитрость, позволяющая DMA прочитать только реестр IDR High Byte Works!
Данные Pixel прекрасно читаются через DMA в буфер.
Затем буфер записывается в ЖК -дисплей, от 1 до 1, 320x240 пикселей разрешение.

Я использовал QVGA 7.5 кадров в секунду Настройки, а SPI записывает в ЖК -дисплей!

Есть только одна большая вещь: цвета несчастны, совершенно неправильно, переписываются, под нарязные...
Я пытался сдвинуть с одним байтом данные, записанные в ЖК -дисплей, но не помог.
И если движение на рисунке высокое, то изображение каким -то образом обновляется намного медленнее. Импульсы все еще в порядке, но содержание изображения медленно обновляется.
Можно выделить только контуры.
Я не знаю, какие настройки используются Lib of Indrekluuk, но, похоже, это не самое лучшее.

Rogerclark
Ср. 02 августа 2017 г. 12:37
Спасибо, Стив

Было бы интересно увидеть ваш код.

Re: Порядок цвета

Хитрость сдвигает один байт, который много времени выпустит для канала, который охватывает границу байта (это может быть зеленый канал, но мне нужно дважды проверить).

Просто сумасшедшая мысль, но могли бы мы запустить 2 разных передачи DMA из GPIO, что смещено на 1 байт друг от друга и имел счетчик счетчиков 2 байта ?

эн.глин. DMA 1 пишет в память

Байты 1, 3, 5, 7 и т. Д

DMA 2 пишет в память

Байты 0, 2, 4, 6

Но DMA 2 должен быть запущен 1 входной тактовой цикл после DMA 1

victor_pv
Ср. 02 августа 2017 г., 4:31
[Rogerclark - Ср. 02 августа 2017 г. 12:37] - Спасибо, Стив

Было бы интересно увидеть ваш код.

Re: Порядок цвета

Хитрость сдвигает один байт, который много времени выпустит для канала, который охватывает границу байта (это может быть зеленый канал, но мне нужно дважды проверить).

Просто сумасшедшая мысль, но могли бы мы запустить 2 разных передачи DMA из GPIO, что смещено на 1 байт друг от друга и имел счетчик счетчиков 2 байта ?

эн.глин. DMA 1 пишет в память

Байты 1, 3, 5, 7 и т. Д

DMA 2 пишет в память

Байты 0, 2, 4, 6

Но DMA 2 должен быть запущен 1 входной тактовой цикл после DMA 1
Один из способов подумать:
Вы могли бы получить 2 DMA, чередование, используя таймер. Идея высокого уровня:
Установить таймер перезагрузить на 2.
Установите таймер канал x на 1.
Установите канал DMA, подключенный к каналу таймера для передачи от A в B (где A и B могут быть памятью или периферийными адресами). Эта передача произойдет первым, когда счетчик таймера достигнет 1.
Установите канал DMA, подключенный к событию обновления для передачи от C в D (IO или MEM, как выше). Эта передача произойдет второй, когда счетчик таймера достигнет 2. В этот момент таймер также сбросится до 0 и продолжит подсчет, следующий импульс превратится в 1 и вызовет новое событие DMA с каналом сравнением.

Чего я не вижу, как это сделать, это написать их в чередованные адреса памяти.
Каналы DMA могут быть установлены для чтения из 8 -битного порта и записать в 16 -битную позицию памяти, но в этом случае лучшие 8 бит будут 0, поэтому он будет перезаписать 8 лучших битов каждый раз. Кроме того, адрес должен был быть выровнен с 16 битами, поэтому оба канала будут писать более низкие 8 бит в одном и том же половине памяти в памяти. Если бы они могли быть выровнены до 8 бит, то вы могли бы использовать этот режим 8 -битного до 16бита, и они будут записывать только 0 в топ -8 бит, которые будут перезаписаны в следующей записи DMA, но, как я уже сказал Чтобы быть согласованным с настроенным размером, если я правильно помню, поэтому для 16 -битного режима он нуждается в адресе, выровненном по этому поводу.

Вы можете написать 2 различных буфера с DMA с таймером, а затем использовать программное обеспечение для их переплета, но требует обработки программного обеспечения.

В таймерах также есть интересный режим. Намерение должно использоваться для перезагрузки значений в несколько регистров сравнения или из нескольких каналов с одним событием в таймере. Я использую его для загрузки значений PWM в 2 канала таймера одновременно, чтобы воспроизводить стереоалекторы.
В любом случае, работает так:
Вы устанавливаете специальную конфигурацию в таймере. Затем вы сообщаете таймеру, сколько трансферов вы хотите (от 1 до 4, если я правильно помню). Затем вы настраиваете DMA в специальный регистр таймера и устанавливаете периферийное приращение к NO в DMA. Этот специальный регистр альтернативно загружает значения в каждый канал, который вы хотели использовать (они должны быть последовательными).
Как только таймер запускает DMA, например, из -за события обновления, поскольку достиг значения перезагрузки, он запускает 2 DMA сразу. Так:
  • Таймер 1 достигает значения ARR и сбрасывается до 0.
  • Вызывает событие обновления
  • Событие обновления вызывает 2 запроса DMA.
  • Канал DMA читает из памяти X и записывает в регистр таймера y.
  • Канал DMA читает из памяти x+1 и записывает в регистр таймера y (снова).
  • Таймер продолжает считать, и когда он достигает повторений ARR сверху.
Если я правильно помню, специальная конфигурация для 2 передачи одновременно выполняется через регистры таймера. Он может быть настроен другим способом, поэтому для чтения 2 значений из регистра и написать их на 2 последовательных адреса в памяти.
Таким образом, используя это, вы можете использовать его для чтения 2 значений из порта GPIO и написать их по 2 последовательным адресам, но 2 чтения будут однозначно за другим, на полной скорости процессора, так что это может быть не то, что вы хотите.

Мне интересно, почему вы хотите использовать 2 канала увеличения 2 байта каждый? Разве вы не можете использовать 1 канал и заставить его прочитать количество необходимых байтов, и он напишет их последовательно?

Стивестронг
Ср. 02 августа 2017 г. 8:28 утра
Мое решение довольно простое, хотя потребовалось много времени, чтобы провести эксперименты с различными методами.

Я использую свободный запуск таймера 2 в сочетании с режимом сброса подчиненных работ, а сигнал на Ti2 настроен как вход захвата.
Каждый раз, когда наступает низкий импульс (сигнал PCLK) на Ti2 (PA1), таймер получает сброс и генерируется событие обновления, которое запускает DMA для чтения битов GPIO 7..15 (высокий байт) и хранить это значение в буфере.
В конце концов, прочитаются все байты для полных линий (опрос конечный флаг передачи канала DMA), эти байты просто передаются в ЖК -дисплей.

Чтобы это работало, я внес несколько изменений:
1. Оптимизируйте ILI9341 LIB DC и CS PIN -комбинезон (не был вполне необходим для этого проекта, но он добавил небольшой скорость в GraphicStest)
+ Добавлена ​​новая функция для написания нескольких пикселей с помощью SPI.dmasend (): void pushColors(uint16_t * ptr, uint16_t nr_pixels);

Rogerclark
Ср. 02 августа 2017 г. 10:49
Спасибо, Стив

Но я не совсем понимаю.

Вы все еще отправляете каждый пиксель на дисплей индивидуально ? как в примере orignal пример из Индреклуука

Я пишу полные строки на дисплее, используя DMA

Но я должен использовать программное обеспечение для байтового обмена.

В моем текущем коде я использую тот же код для чтения с камеры, а затем в конце каждой строки я байтовый обменивает буфер и отправляю всю линию в одну передачу DMA, используя DMASendasync на дисплей

Я мог бы изменить код так, чтобы, когда он прочитал пиксели с камеры, он выполнял байт, поддержав 2 указателя или *(указатель +1) = пиксель и т. Д.
Но это не имеет никакого значения для времени, так как я не мог превышать 7.2 кадры на QVGA, так как ограничение в том, что кадр нельзя отправить на дисплей достаточно быстро.

На самом деле, теперь, когда я добавил чрезвычайно разгрузка в меню скорости процессора, я думаю, что, возможно, 12 FPS @ QVGA может быть возможным, так как я проверил часы ILI9341 DEMO @ 128 МГц (с помощью SPI Div 2 часы = 64 МГц !!!!) и, кажется, работает нормально.

Я не прикреплял логический анализатор к часам SPI, но графический тест, казалось, работал очень быстро.

В любом случае, основным преимуществом DMA будет то, что прерывания не должны быть отключены, поэтому USB все равно будет работать.


Итак, дайте нам знать, когда и если вы можете поделиться своим кодом DMA

Спасибо

Роджер

Стивестронг
Ср. 02 августа 2017 г. 11:28
Роджер, я упомянул в своем посте, что добавил новую функцию, которая использует DMA,:
[Стивестронг - Ср. 02 августа 2017 г. 8:28] - + Добавлена ​​новая функция для написания нескольких пикселей с помощью SPI.dmasend (): void pushColors(uint16_t * ptr, uint16_t nr_pixels);

Rogerclark
Ср. 02 августа 2017 12:21
Хорошо.

Я думал, что обмен байта DMA будет на входе.

На самом деле, даже если байтовый обмен должен был быть сделан в программном обеспечении, может быть время, если все буферизовано, так что одна линия может появиться по DMA во время предыдущей строки, если она заменяется в SW, то вывод через DMA может быть.

Но я полагаю, что это может потребоваться двойная буферизация как на входе, так и на выводе

Стивестронг
Ср. 02 августа 2017 12:31
Подумав немного больше об этом, я думаю, что теперь, что обмена байта может быть сделано легко без дополнительной обработки программного обеспечения.
Фон:
- Порядок, в котором данные RGB565 хранятся в памяти, является: RG1, GB1, RG2, GB2, ...
- В 8 -битном режиме данные SPI отправляются в том же линейном порядке, в котором они были написаны: RG1, GB1, RG2, GB2, ...
- В 16 -битном режиме высокий байт значения UINT16_T будет отправлен первым над SPI, и из -за маленькой эндюнессы первым отправленным байтом будет второй написанный байт, за которым следует первый написанный байт: GB1, RG1, GB2, RG2, ...

Таким образом, обмена байтов сводится к изменению размера данных SPI между 8 битами до 16 бит перед использованием SPI.dmasend ().
:!:
Не забывайте, фактический режим SPI по умолчанию для ILI9341 LIB - это 16 -битный. SPI.setDataSize(DATA_SIZE_8BIT); // set to 8 bit mode SPI.dmaSend(...); // tft.pushColors(...); SPI.setDataSize(DATA_SIZE_16BIT); // set back to 16 bit mode

Стивестронг
Ср. 02 августа 2017 г. 16:17
Здесь код. У меня сейчас хорошая картина с этой версией.
Это может не работать для вас, так как я сказал, что многие локальные изменения были внесены дополнительно, но концепция есть.

Стивестронг
Ср. 02 августа 2017 г., 17:55
Похоже, что я нашел хороший рабочий предел, он находится на 11 кадров в секунду, и предварительное значение 3.

Следующим уровнем будет предварительное значение 2, которое будет генерировать 14.5 кадров в секунду, но это именно тот предел, когда передача SPI полностью заполняет горизонтальный интервал высадки. В этом случае спорадически передача SPI перекрывает перенос DMA Pixel DMA, который проявляется в спорадических неправильных пикселях на дисплее.

Я пытался использовать SPI.dmasendasync (), но это вообще не помогает. Когда два передачи DMA перекрываются, они сильно влияют (задерживают) друг с другом, так что данные пикселя повреждены => непригодный.
[Blue = href, желтый = spi clk]
OV7670Live14.6FPS.JPG
OV7670Live14.6fps.JPG (51.15 киб) просмотрено 354 раза

Rogerclark
Ср. 02 августа 2017 22:05
[Стивестронг - Ср. 02 августа 2017 12:31] - Подумав немного больше об этом, я думаю, что теперь, что обмена байта может быть сделано легко без дополнительной обработки программного обеспечения.
Фон:
- Порядок, в котором данные RGB565 хранятся в памяти, является: RG1, GB1, RG2, GB2, ...
- В 8 -битном режиме данные SPI отправляются в том же линейном порядке, в котором они были написаны: RG1, GB1, RG2, GB2, ...
- В 16 -битном режиме высокий байт значения UINT16_T будет отправлен первым над SPI, и из -за маленькой эндюнессы первым отправленным байтом будет второй написанный байт, за которым следует первый написанный байт: GB1, RG1, GB2, RG2, ...

Таким образом, обмена байтов сводится к изменению размера данных SPI между 8 битами до 16 бит перед использованием SPI.dmasend ().
:!:
Не забывайте, фактический режим SPI по умолчанию для ILI9341 LIB - это 16 -битный. SPI.setDataSize(DATA_SIZE_8BIT); // set to 8 bit mode SPI.dmaSend(...); // tft.pushColors(...); SPI.setDataSize(DATA_SIZE_16BIT); // set back to 16 bit mode

Rogerclark
Ср. 02 августа 2017 г. 22:08
[Стивестронг - Ср. 02 августа 2017 г., 17:55] - Похоже, что я нашел хороший рабочий предел, он находится на 11 кадров в секунду, и предварительное значение 3.

Следующим уровнем будет предварительное значение 2, которое будет генерировать 14.5 кадров в секунду, но это именно тот предел, когда передача SPI полностью заполняет горизонтальный интервал высадки. В этом случае спорадически передача SPI перекрывает перенос DMA Pixel DMA, который проявляется в спорадических неправильных пикселях на дисплее.

Я пытался использовать SPI.dmasendasync (), но это вообще не помогает. Когда два передачи DMA перекрываются, они сильно влияют (задерживают) друг с другом, так что данные пикселя повреждены => непригодный.
[Blue = href, желтый = spi clk]
OV7670Live14.6fps.JPG

Возможно, можно ли поиграть с PLL и прескалером камеры, чтобы получить разные пиксельные часы, чтобы мы могли получить более высокий FPS (до 14)?

Кстати, я попытался разгонять процессор @ 128mhz, он не выглядит хорошо, я думаю, что камера не поддерживает эти высокие пиксельные часы (PLL Out of Range?), цвета не правы, частота обновления ниже, несмотря на значение предварительного прекалера 2 более высоких.

Лучшая рабочая производительность для QVGA достигается с помощью перегодного процессора при 80 МГц -> 12.5FPS = ОК.

Я прикрепляю код как LIB, извлекать в /arduino /библиотеки, включая эскиз в качестве примера.
Для этого, последнее главная версия моего репо необходим.
Спасибо.

Я думаю, что нам нужно заставить его работать на уровне 72 МГц, чтобы сохранить USB, если это возможно, даже если это имеет более низкую частоту кадров

Rogerclark
Ср. 02 августа 2017 11:57
@stevestrong

Я скачал тебя репо и использовал его вместо моего репо, и я скопировал тебя на молнии, чтобы сделать библиотеку, но это не сработало для меня

Я получаю пустой экран


Пса. Я видел твое исправление в DMA.h для опечатки, поэтому я решил ваше исправление для этого в своем репо.

Спасибо

Роджер

Стивестронг
Чт, 3 августа 2017 г., 6:16
Роджер, вы проверили схему соединения между BP и камерой? Это в примере iNO -файла.

Rogerclark
Чт, 3 августа 2017 г., 6:59
[Стивестронг - Четверг 3 августа 2017 г., 6:16 утра] - Роджер, вы проверили схему соединения между BP и камерой? Это в примере iNO -файла.
Нет.

Я только что взял вас в Zip -файл и использовал его как библиотеку

Мне также нужно было первоначально добавить потоковую передачу.H в папку Sketch, но я подозреваю, что у вас может быть это в вашем репо

В любом случае, я скачал ваш репо, заменил мой и попробовал, но получил пустой экран.

Тогда у меня не хватило времени сегодня утром, потому что мне пришлось начать работу.

Как теперь это конец рабочего дня для меня, я попробую еще раз сегодня вечером.

КСТАТИ. Одно полезное дополнение, которое у меня было в коде, - это прошить светодиод в каждом кадре.
Я могу добавить этот код, так как он помогает узнать, обнаруживает ли код VSYNC

Стивестронг
Чт, 3 августа 2017 г., 7:44
[Rogerclark - Четверг. 03 августа 2017 г. 6:59 утра] - Одно полезное дополнение, которое у меня было в коде, - это прошить светодиод в каждом кадре.
У меня это тоже в коде, но каким -то образом не работал для меня, и не терял времени, чтобы узнать, почему. digitalWrite(LED_PIN, !digitalRead(LED_PIN)); // does not work for me

Rogerclark
Чт, 3 августа 2017 г., 7:54
Ммм

Вы используете разные контакты для данных от камеры до исходного примера !

Также я использовал разные булавки для ILI9341

Однако я попробовал свой старый набросок, и он не работает, поэтому я думаю, что, возможно, один из проводов освободился.

На самом деле, мне нужно будет переоценить мою версию репо на случай, если это как -то связано с вашим репо

Я сделаю несколько тестов позже после нашего вечернего ужина

Стивестронг
Чт, 3 августа 2017 г., 7:59
[Rogerclark - Четверг 3 августа 2017 г., 7:54 утра] - Также я использовал разные булавки для ILI9341
Да, действительно, извините за путаницу, я просто взял свои ранее используемые булавки для ЖК -дисплея и добавил те, которые из камеры, которые должны быть такими же, как в примере Github (https: // github.com/indrekluuk/liveov7670_stm32-arduino), с необходимым изменением соединения PCLK к PA1 (TI2) вместо PB4.

Кстати, я бы порекомендовал вам этот пиар: https: // github.com/stevstrong/arduino_stm32/pull/2. Это жизненно важно для хорошего примера захвата рабочего таймера.

Rogerclark
Чт, 3 августа 2017 г. 8:06 утра
Ммм

Что -то еще отличается в вашем репо.

Возможно, ILI9341 lib

Я перешел обратно на свой магистр репо, и мой старый пример кода работает нормально (мне нужно выбрать -O2 в новом меню, но это все)

Но когда я использую ваше репо, экран остается зеленым

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

Мне нужно избирательно изменить вещи, так как ваш Spi Lib, а также ILI9341

Стивестронг
Чт, 3 августа 2017 г. 8:18 утра
Вы можете опубликовать свой код здесь? Тогда я могу проверить его на своем столе и выяснить различия.
Но на первом виде я не могу представить, что SPI приведет к тому, что ваш код не работает. Я только что очистил его и добавил новую функцию.
OTOH, ILI9341 LIB может быть критическим, что, в свою очередь, работает для вас (зеленый экран).

Rogerclark
Чт, 3 августа 2017 г. 8:35 утра
Это ILI9341 LIB, который мешает моему коду работать

Я не уверен, почему.

Я прикрепил свой старый код.

Он удваивает пиксель и линии, чтобы преобразовать из QQVGA из камеры в QVGA (дисплей ILI9341)

Код немного взломан, но он не так сильно отличается от оригинала.

Примечание. Моя распинания дисплея отличается от вашей, как и сигналы камеры (кроме i2c)

Стивестронг
Чт, 3 августа 2017 г. 8:46
На первом виде я упускаю настройку DC для данных и активации CS для ЖК -дисплеев до SPI отправить.
Я не знаю, почему это сработало для тебя ... : шок: Вы установили штифт CS, прикрепленный к GND?

Эта проблема была именно той причиной, по которой я реализовал функцию pushColors (), потому что внутри этой функции эти необходимые элементы управления устанавливаются по мере необходимости.

Кстати, мы могли бы достичь 20..Скорость обновления ЖК-дисплея с 40 кадров в секунду с разрешением камеры QQVGA путем удвоения пикселей и линий и с использованием чтения пикселей на основе DMA, с входной двойной буферизацией.
Было бы интересно попробовать, как далеко мы можем зайти, повышая это более низкое разрешение?

Rogerclark
Чт, 3 августа 2017 г., 10:07
Я подключил все 3 контрольных штифта

#define tft_cs pa2
#define tft_dc pa0
#define tft_rst pa1

И не умышленно тянул CS в GND все время.

Я сделал GIT Diff, но он обнаружил множество небольших различий между двумя различными версиями библиотеки, поэтому трудно понять, какое изменение остановило его работать

Оригинальный графический тест работает нормально, а ваш экран прозрачный и начальный текст работает ОК.

Так что, похоже, это просто ваша функция, чтобы отправить изображение, которое может не работать для меня

Концзакп
Чт, 3 августа 2017 г. 10:15 утра
[Стивестронг - Вторник 01 августа 2017 г., 14:20] - Вам не нужно переключать CS и DC между последовательными чтениями данных (SPI.переводы...)
Даже без переключения CS и DC между чтениями я все еще получаю 255 255 255. Также установка SPI.setDatasize (data_size_8bit); Прежде чем чтение данных не помогает :плакать:

Rogerclark
Чт, 3 августа 2017 г., 10:59
@stevestrong

КСТАТИ. Причина, по которой светодиод не мигает для вас, заключается в том, что Pinmode установит его на вывод, и не настройка, а не настройка

Я скопировал PinMode для настройки и переместил #Define в верхнюю часть файла, а светодиод сейчас работает.

Я не уверен, почему ты переехал

// pb4 - пиксельные часы

к

// pa1 - Pixel Clock Pclk

я.e Мое картирование штифта камеры
// A8 - camera clock // PB3 - href // PB4 - pixel clock // PB5 - vsync // PB6 - i2c Clock // PB7 - i2c data // PB8..PB15 pixel byte

Стивестронг
Чт, 3 августа 2017 г., 11:34
Роджер, я сменил PCLK с PB4 на PA1, потому что PCLK должен быть подключен к входу захвата таймера для DMA.
Это также означает, что #define OV7670_PIXEL_CLOCK ((*idr) & BIT4) //((*GPIOB_BASE).IDR & BIT4)

Стивестронг
Чт, 3 августа 2017 г., 11:38
[Концзакп - Четверг. 03 августа 2017 г. 10:15] - Даже без переключения CS и DC между чтениями я все еще получаю 255 255 255. Также установка SPI.setDatasize (data_size_8bit); Прежде чем чтение данных не помогает :плакать:
Я проверю это вечером.

Просто для записи: Вспомогательная информация: ILI9341.PDF
- глава.7.6.2. 4-линный серийный интерфейс, стр. 64
- глава.8.2.24. Читая память (2EH), стр. 116

Концзакп
Чт, 3 августа 2017 г., 11:48
@stevestrong
Ты мой Спаситель - я все пробовал.

Rogerclark
Чт, 3 августа 2017 12:03
Существуют небольшие накладные расходы, поскольку вам нужно установить адресное окно, но оно все равно может дать более высокую кажущуюся частоту кадров

Стивестронг
Чт, 3 августа 2017 г., 19:23
Роджер, я только что загрузил свой репо, скомпилировал эскиз, загруженный -> оно работает.

Теперь я борюсь с чтением, я всегда получаю 0.
http: // www.Avrfreaks.net/comment/223451 ... NT-2234511
Попытка синхронизировать ILI9341_STM LIB с этим от Адафрут.

Rogerclark
Чт, 3 августа 2017 г., 22:00
Я думаю, что Концзакп пытался прочитать работу

Я еще не исследовал это

Я распущу свои пиксельные часы и подключу их к тому же пинке, который вы используете

Rogerclark
Чт, 3 августа 2017 г. 11:36
@stevestrong

КСТАТИ.

Я выяснил, почему мой код работает, хотя CS не навсегда не натягивается

Это потому, что заполнить листья CS Low, так как он не тянет его высоко после завершения dmamesend

Это потенциально ошибка в библиотеке ILI9341, если кто -то хотел использовать дисплей на том же канале / контактах SPI, что и другое устройство

Я не уверен, что мой код сработает, если CS будет высоко ориентирован на библиотеку, а затем на дисплей, а затем на низком уровне, так как можно было бы отправить новое AddressWindow на дисплей, а не сгибание на предыдущем , fillRect (), команда

Стивестронг
Пт, 04 августа 2017 г., 7:32 утра
Хорошо, тогда это понятно.
Я думаю, что это FillScreen () функция, которая пропускает CS, возвращается к высоту (Смотрите эту линию), fillRect () имеет его (здесь).
В моем репо я исправил это с последним коммитом (Смотрите здесь), это внутри пиара, я отправил тебе.

OTOH, setAddrwindow () также пропускает его, поэтому он сработал для вас.

Кстати, я планирую сделать еще одну оптимизацию на этой LIB, чтобы удалить часть переключения вывода DC: это будет выполнено только в функции writeCommand (), оставшееся время он может оставаться высоким (доступ к данным).

Rogerclark
Пт, 04 августа 2017 г., 7:43
Вероятно, несколько мест, чтобы не установить CS High.

Это единственное заполнение, которое заставило его работать для меня.

Rogerclark
Пт, 04 августа 2017 г. 10:36
Стив

Спасибо. Ваш код сейчас хорошо работает для меня.

Удивительная работа.....

Я переписывал свою доску. Я использовал PA1 для TFT (RESET), поэтому я переместил это в PA3 и перенести Pixel Clock на PA1

Первоначально я использовал вашу копию репо, но теперь я добавил pushColors () в существующую версию библиотеки ILI9341, чтобы любой, кто использует последнюю копию, теперь мог использовать ваш код


еще раз спасибо...


Пса. Я предполагаю, что следующее, что нам нужно для работы, - это читать с дисплея, но это звучит сложнее, чем мы себе представляли.

Стивестронг
Сб 05 августа 2017 г. 8:21
Я наконец получил работу по чтению пикселей, решение было слишком простым :)
Чтение регистров и данных по Граму сейчас действительно работает.

Подсказка заключается в том, что для чтения часов SPI может быть не выше 24 МГц (информация, взятая из оригинальной Adafruit Lib).
И это CS PIN Должен быть низко В течение всего процесса чтения он может не переключаться.

Я также сделал дальнейшее улучшение скорости и другие вещи на ILI9341 LIB.

Вывод из графического теста (в сочетании с тестированием чтения):
ILI9341 Test! Display Power Mode: 0x9C MADCTL Mode: 0x48 Pixel Format: 0x5 Image Format: 0x9C Self Diagnostic: 0xC0 Read single pixel test ------------------------------ Write pixel: 0x1234 Read pixel: 0x1234 Read multiple pixel test ------------------------------ Write pixels: 0x1234, 0x5678, 0x9012, 0x3456 Read 4 pixels: 0x1234, 0x5678, 0x9012, 0x3456 Benchmark Time (microseconds) Screen fill 170777 Text 30574 Lines 151856 Horiz/Vert Lines 15086 Rectangles (outline) 10120 Rectangles (filled) 354913 Circles (filled) 93002 Circles (outline) 119291 Triangles (outline) 34098 Triangles (filled) 139567 Rounded rects (outline) 43011 Rounded rects (filled) 400061 Done!

Rogerclark
Сб 05 августа 2017 г. 8:28 утра
Спасибо
Я притяну твое репо своей местной машине

Rogerclark
Сб 05 августа 2017 г. 9:03
Стив

Это не работает для меня

Вы тоже обновили свою библиотеку ?

Когда я вытащил, я получил замену библиотеки ILI9341 и обновленный графический тест (и Freertos изменяется)

Но когда я запускаю эскиз камеры, который работал нормально, просто получите мерцающий дисплей

Работает ли новейший ILI9341 LIB с камерой ?

КСТАТИ. Графический тест нуждается в потоковой передаче, но даже когда я локально тяну ваш репо, он не находит потоковую передачу.H, поэтому я должен вручную поместить его в папку эскиза.

Редактировать

Графический тест тоже не работает для меня.

Я подозреваю, что это связано с изменениями, которые вы внесли в CS

Стивестронг
Сб 05 августа 2017 г. 10:10
Хм, я не знаю, что сказать, я только что вытащил свой чистый репо, и GraphicStest и Live OV7670 бегут нормально.

Rogerclark
Сб 05 августа 2017 г. 10:31
Привет, Стив

Не беспокойся

Я посмотрю, смогу ли я выяснить, почему это не работает для меня.

Rogerclark
Сб 05 августа 2017 г. 11:02
Стив

Я попытался добавить ваш код для чтения пикселей в текущую библиотеку без всех других ваших изменений, но в настоящее время он не читает никаких данных.

Возможно, я сделал что -то не так, когда копировал код и изменял его, но теперь мне становится слишком поздно выяснить, что пойдет не так, так как я думаю, что мне нужно подключить логический анализатор к доске, Чтобы подтвердить, что отправляется на это

Я постараюсь посмотреть еще раз завтра, но в то же время, возможно, вам лучше застегнуть свой ILI9341 LIB и опубликуйте это здесь или, возможно, также для генерала, и посмотрите, смогут ли еще несколько людей проверить это.

Концзакп
Сб 05 августа 2017 г. 11:15 утра
Я проверю это томороу . . .

Rogerclark
Солнце 06 августа 2017 3:17
Привет, Стив

Я выяснил, почему пример вашей камеры не работал с новой библиотекой ILI9341

Это потому, что в строке 135 у вас есть штифт отладки, определяемый как PA0, и я использую этот PIN -код для DICE DC PIN

Я подозреваю, что изменения в библиотеке, в которых вы теперь возвращаете CS до высокого уровня после перевода, изменили то, как состояние DC было заблокировано при изменении

В любом случае. Теперь, когда я изменил булавку отладки на PB0
//----------------------------------------------------------------------------- #define DBG_PIN PB0 #define SET_DBG digitalWrite(DBG_PIN, HIGH) #define CLR_DBG digitalWrite(DBG_PIN, LOW) //-----------------------------------------------------------------------------

Стивестронг
Солнце 06 августа 2017 15:27
Роджер, приятно, что наконец работает.
Извините за штифт отладки, я удалю я, я использовал его только на короткое время.

Во всяком случае, я прошел еще несколько экспериментов, теперь я могу пойти с частотой кадров с 11 кадров в секунду до до до 12 кадров в секунду Используя другой источник часов.

Первоначально XCLK взят из MCO (вывод CPU Clock) и составляет 36 МГц. Затем он подключается к камере к множителю PLL (в настоящее время обходит), а затем к пиксельному генератору через прескалер.
На самом деле на 11 кадров в секунду прокалер имеет значение 3 (на самом деле означает разделение часов от PLL на 3+1) перканацию на пиксельные часы 9 МГц..

Но эквивалентная частота пикселей также может быть сгенерирована с выходом ШИМ 36 МГц, разделенной My 4 (= 9 МГц) и активной камеры PLL для умножения на 4. Прескалер затем получает те же 36 МГц, что и раньше, и разделив его на 4, мы получаем те же FPS, что и ранее.

С помощью простой трюки, если я установите выход ШИМ 36 МГц, разделенный на 3 (вместо 4 до) приведет к XCLK 12 МГц, умноженного на PLL x4 = 48 МГц.
Затем, используя более низкую камеру Прескалер 4 (разделите на 5), приводит к пиксельным часам 9.6 МГц, ~ 12 кадров в секунду.

Это на 8% увеличивается в FP, не разгружая процессор и имея рабочую серийную USB.
Изображение выглядит немного лучше.

Можно пойти дальше и разгонять процессор и попробовать разные комбинации дифровых делителей ШИМ и Прескалеров, чтобы получить, возможно, еще больше FPS.

РЕДАКТИРОВАТЬ
Забавно, у меня теперь есть работа 15 кадров в секунду, с хорошей картиной. Я не знаю, почему это работает, но это делает.
https: // github.com/stevstrong/liveov7670_stm32
(Код очищен, изменил MCO на PWM)

Концзакп
Солнце 06 августа 2017 18:30
@stevestrong

Я собирался проверить вашу либера.час". Что это и где его найти?
.

Стивестронг
Солнце 06 августа 2017 18:33
Поиск в сети/GitHub для ArduinoStreaming lib.
Или здесь: ViewTopic.PHP?f = 9&T = 2425

Концзакп
Солнце 06 августа 2017 18:43
хорошо. Теперь я получаю ошибки с DMA, как это:
/arduino-1.6.9/hardware/Arduino_STM32_Camera/STM32F1/libraries/LiveOV7670_STM32/examples/LiveOV7670stm32/LiveOV7670stm32.ino: In function 'void DMA_Setup()': /arduino-1.6.9/hardware/Arduino_STM32_Camera/STM32F1/libraries/LiveOV7670_STM32/examples/LiveOV7670stm32/LiveOV7670stm32.ino:115:5: warning: 'void dma_setup_transfer(dma_dev*, dma_channel, volatile void*, dma_xfer_size, volatile void*, dma_xfer_size, uint32)' is deprecated (declared at /arduino-1.6.9/hardware/Arduino_STM32_Camera/STM32F1/system/libmaple/stm32f1/include/series/dma.h:563) [-Wdeprecated-declarations] dma_setup_transfer(DMA1, DMA_CH2, ^ /arduino-1.6.9/hardware/Arduino_STM32_Camera/STM32F1/libraries/LiveOV7670_STM32/examples/LiveOV7670stm32/LiveOV7670stm32.ino:118:18: warning: 'void dma_setup_transfer(dma_dev*, dma_channel, volatile void*, dma_xfer_size, volatile void*, dma_xfer_size, uint32)' is deprecated (declared at /arduino-1.6.9/hardware/Arduino_STM32_Camera/STM32F1/system/libmaple/stm32f1/include/series/dma.h:563) [-Wdeprecated-declarations] (DMA_MINC_MODE));//| DMA_CIRC_MODE)); ^ /arduino-1.6.9/hardware/Arduino_STM32_Camera/STM32F1/libraries/LiveOV7670_STM32/examples/LiveOV7670stm32/LiveOV7670stm32.ino: In function 'void loop()': LiveOV7670stm32:223: error: 'DMA_ISR_TCIF' was not declared in this scope while ( !(dma_get_isr_bits(DMA1, DMA_CH2) & DMA_ISR_TCIF) ) { ^ LiveOV7670stm32:233: error: 'DMA_ISR_TCIF' was not declared in this scope if ( dma_get_isr_bits(DMA1, DMA_CH2) & DMA_ISR_TCIF ) { ^ exit status 1 'DMA_ISR_TCIF' was not declared in this scope

Стивестронг
Солнце 06 августа 2017 18:46
Тебе нужно мое репо. https: // github.com/stevstrong/arduino_stm32

Концзакп
Солнце 06 августа 2017 г., 19:18
Теперь это компиляция. Но кажется, что у вас есть разные соединения между камерой STM и TFT, чем мои. Я должен проверить их и перепродавца на вашем пути.

Стивестронг
Солнце 06 августа 2017 8:06 вечера
Только PA1 и булавки данных важны, остальные можно переопределить, когда.

Rogerclark
Солнце 06 августа 2017 21:58
Стив

Я не знаю, делаю ли я расчет неправильно, но..

Если SPI на дисплее работает на Div2, это 36 МГц.

Таким образом, теоретические максимальные пиксели в секунду составляют 36 000 000 /16, так как они 16 -битные пиксели.

Это равно 2250 000

Дисплей 320 x 240 пикселей. Так что это 76 800 пикселей.

Таким образом, количество раз в секунду, что SPI может отправлять все пиксели, будет 2 250 000 /76 800

Который чуть более 29


Конечно, это потребует, чтобы данные были отправлены на дисплей в то же время, как и его получение от камеры, и было бы невозможно получить 29 кадров в секунду.

Но использование двойной буферизации, более высокая частота кадров, чем вы в настоящее время достигаете, может быть возможно.

Потребуется только 1 линия, чтобы быть двойной буферизацией (круговой буфере также был бы в порядке, если в длину не менее 2 линий)

Стивестронг
Солнце 06 августа 2017 22:34
[Rogerclark - Солнце 06 августа 2017 21:58] - Но использование двойной буферизации, более высокая частота кадров, чем вы в настоящее время достигаете, может быть возможно.
Да, теоретически. Но не на практике.

Мои эксперименты показали, что с этим методом отбора проб пикселя (DMA) невозможно получить более высокую частоту кадров.
SPI DMA будет сильно влиять на сканирование пикселей на основе DMA (что очень важно), так что пиксели теряются. Я думаю, что это архитектурное ограничение оборудования. Это приводит к поврежденному изображению.
Я прикрепил в одном из моих предыдущих постов изображение, где Href и DMA перекрывались. Эта небольшая перекрывающаяся область вызвала уже искаженные цвета на всей картине.

Даже с 15 кадров в секунду я должен исправить (очистить до 0) первые два пикселя, которые иногда будут искажены.
Самое смешное, что я тоже попробовал 13 кадров в секунду, но это не сработало (поврежденное цветное изображение).
Поэтому я подозреваю, что на 15 кадров в секунду DMA на самом деле читает с одной задержкой пикселя - внутренний таймер занимает, вероятно, много тактовых циклов, чтобы вызвать DMA.

Rogerclark
Пн, 07 августа 2017 г. 1:09
Спасибо, Стив

Я думал, что, поскольку тест @ @Racemaniac управлял несколькими одновременными передачами DMA без заметных потерь в производительности, может быть возможна более высокая частота кадров.
Но я понимаю, что время отбора проб пикселя камеры имеет решающее значение, и передачи SPI должны задержать это достаточно, что приводит к повреждению изображения повреждено.

КСТАТИ.
Вы пытались изменить приоритет SPI DMA ?

Я вижу, что в void spiclass :: dmatransferset (void *antrmitbuf, void *recembuf) {
это имеет

dma_set_priority (_currentsetting->Spidmadev, _currentsetting->spirxdmachannel, dma_priority_very_high);

И я не уверен, что этот параметр все еще активен, когда используется DMASEND, BECASE

Damasendset есть только

dma_set_priority (_currentsetting->Spidmadev, _currentsetting->spitxdmachannel, dma_priority_low);

и не изменяет приоритет получения

Но я думаю, что, возможно, это не имеет значения, поскольку мы только отправляем и не получаем ??

Виндиам
Пн, 07 августа 2017 г., 3:03
Здравствуйте, я прочитал этот пост, и я также делаю дисплей OV7670 на плате Bluepill. Есть ли какие -либо возможности, что данные могут быть отправлены в 320x240 с кадром, как 15+ на USB -сериал? Я написал эскиз обработки, чтобы отобразить его, но теперь я могу буферировать только одну небольшую область, такую ​​как 100*80 из -за 20 -километрового плана, и отправлять данные после каждого кадра с надлежащими задержками (убедитесь, что он отправить). Допускает ли DMA передача USB?

Rogerclark
Пн, 07 августа 2017 г., 3:27
USB Serial не предназначен для обработки большой пропускной способности, необходимой для обработки изображений.
Он не использует DMA для передачи данных

Есть некоторые потоки, где люди проверяли максимальную пропускную способность серийного USB, но он не будет достаточно быстрым, чтобы перенести более 2 МБ в секунду на ПК (необходимый для 320x240 @ 2 байта на пиксель @ 15 кадров в секунду)

Я бы порекомендовал вам поиграть с последней версией Стива и держать DMA от камеры, но на гораздо ниже частоты кадров и попытаться перенести одну линию за раз в USB -сериал, по линии за раз.
(На самом деле я не уверен, что USB -буфера достаточно для целой линии. Вам нужно проверить код ядра и потенциально увеличить USB -буфер с толку)

Стивестронг
Пн, 07 августа 2017 г. 7:39
[Rogerclark - Пн, 07 августа 2017 1:09] - Но я думаю, что, возможно, это не имеет значения, поскольку мы только отправляем и не получаем ??
Правильный. Получение SPI должен иметь более высокий PRIO, чем отправка SPI, но мы ничего не получаем в этом проекте за SPI, так что это не блокирует нас.

Стивестронг
Пн, 07 августа 2017 г. 7:43 утра
@Windyyam
Максимальная пропускная способность по сравнению с сериалом USB я измерял ~ 600 кбит / с, вам понадобится ~ 2.3 Мбит / с, что невозможно.
Может быть, 4FP.

Я не знаю, есть ли некоторые адаптеры с последовательным USB, которые поддерживают такую ​​высокую пропускную способность, вы можете в конечном итоге отправить данные через USART.

Виндиам
Вторник 8 августа 2017 г. 3:03
Хорошо, я попробовал с доской Vet6 с 65 -каратным оперативным операцией, этого достаточно, чтобы удерживать один кадр на QQVGA 160*120. Если я прилагаю процедуру чтения с noInterrputs/прерываниями и отправлю все рамки через USB -сериал после этого, я получаю правильный предварительный просмотр
1.jpg
1.JPG (15.14 киб) просмотрено 312 раз

Стивестронг
Вторник 8 августа 2017 г. 5:16 утра
Я не вижу никаких фотографий...

Виндиам
Вторник 8 августа 2017 г. 6:27 утра
О, я загружаю картинку в Photobucket, так что не знаю, почему вы не можете видеть. Просто чтобы знать, кажется, я не могу полагаться на сериал USB, чтобы отправить по линии. Но я видел КомпьютернердАрдуино uno -код на GitHub, не тестируемый, но как он достигает этого на MCU 16 МГц с просто UART....

Пито
Вторник 8 августа 2017 г. 6:53
Как он достигает этого на MCU 16 МГц с просто UART.... Он отправляет данные, пока он читает пиксели на 1MBAUD.

Виндиам
Вторник 8 августа 2017 г. 7:07
[Пито - Вторник 8 августа 2017 г., 6:53 утра] - Он отправляет данные, пока он читает пиксели на 1MBAUD.
Can STM32 USB Serial сделать то же самое, с прерыванием, используя реестр?

Rogerclark
Вторник 8 августа 2017 г. 7:17 утра
Нет.

Операция USB требует включения прерываний.

Виндиам
Вторник 8 августа 2017 г. 7:36 утра
4.jpg
4.JPG (37.17 киб) просмотрено 512 раз

Стивестронг
Вторник 8 августа 2017 г. 7:54 утра
Windyyam, фотографии Photobucket не видят, вместо этого я могу прочитать только «Пожалуйста, обновите свою учетную запись, чтобы включить стороннее хостинг».
Не могли бы вы просто прикрепить изображения «Обычно»?

Виндиам
Вторник 8 августа 2017 г. 8:06 утра
О, извините за это. Я думал, фотобакет может помочь. В моей стране я не могу посетить Dropbox или другой подобный сайт. Я меняю связь там, и это может сработать

Концзакп
Вторник 8 августа 2017 г., 19:08
@stevestrong

Я скачал ваше репо, ArduinoStreaming, которое вы указали мне, а также LiveOV7670 из вашего репо. У меня точно такие же подключения для камеры, как и вы, и немного разные подключения для экрана.
// TFT connection: // PB4 - TFT reset // PA0 - TFT D/C (data/command) // PA2 - TFT chip select // PA5 - TFT SPI CLK // PA6 - TFT SPI MISO // PA7 - TFT SPI MOSI // Camera connection: // PA8 - camera clock // PB3 - HREF // PA1 - pixel clock PCLK // PB5 - VSYNC // PB6 - I2C Clock // PB7 - I2C data // PB8..PB15 - pixel data

Концзакп
Ср. 09 августа 2017 11:38
Я скачал новейшее репо STM из Roger's GitHub, и теперь с вашим репо OV7870, я получаю изображение, как ниже, и через несколько минут он превращается в белый экран:/ а иногда не начинается, как раньше. С помощью этого теста я также использовал потоковую передачу из другого репо (я не знаю, меняет ли он что -либо)
.
Selection_001.jpg
Selection_001.JPG (57.43 киб) просмотрено 473 раза

Стивестронг
Ср. 09 августа 2017 г. 14:35
[Концзакп - Ср. 09 августа 2017 г. 11:38] - Ваше репо отсутствует #define TIMER_CCMR_CCS_OUTPUT 0x0 #define TIMER_CCMR_CCS_INPUT_TI1 0x1 #define TIMER_CCMR_CCS_INPUT_TI2 0x2 #define TIMER_CCMR_CCS_INPUT_TRC 0x3

Rogerclark
Ср. 09 августа 2017 22:29
Стив

Я думаю, что я объединю ваш последний SPI с Master, а также обновлю ILI9341 LIB с вашей версией, чтобы любой мог использовать код OV7670.

Концзакп
Чт 10 августа 2017 г., 10:30 утра
Спасибо, Стив, но я не могу использовать ваш файл bin, потому что у меня есть замены булавки для TFT.
Я сделал шаг назад и снова пробовал код Индреклука для измененных булавок. Все работало нормально. Итак, следующий шаг, который я попытался переписать функцию Readpixel из репо Стивестронга ILI9341 LIB.

в adafruit_ili9341_stm.CPP у меня есть:
void Adafruit_ILI9341_STM::writecommand(uint8_t c) { *dcport &= ~dcpinmask; *csport &= ~cspinmask; spiwrite(c); *csport |= cspinmask; } uint16_t Adafruit_ILI9341_STM::readPixel(int16_t x, int16_t y) { SPI.beginTransaction(SPISettings(24000000ul, MSBFIRST, SPI_MODE0, DATA_SIZE_8BIT)); writecommand(ILI9341_CASET); // Column addr set spiwrite16(x); spiwrite16(x); writecommand(ILI9341_PASET); // Row addr set spiwrite16(y); spiwrite16(y); writecommand(ILI9341_RAMRD); // read GRAM SPI.transfer(0x00); //dummy read uint8_t r = SPI.transfer(0x00); uint8_t g = SPI.transfer(0x00); uint8_t b = SPI.transfer(0x00); cs_set(); SPI.beginTransaction(SPISettings(48000000ul, MSBFIRST, SPI_MODE0, DATA_SIZE_16BIT)); return color565(r, g, b); }

Концзакп
Пт 18 августа 2017 г. 7:36 утра
Поскольку я все еще не мог заставить его работать, я скачал новейшее Wersion of Arduino IDE (чтобы сделать чистую установку) версию 1.8.3.
Автономная версия Toolchain (GCC-ARM-None-EABI-6-2017-Q2-UPDATE) Я получил его отсюда: https: // Разработчик.рука.com/с открытым исходным кодом/g ... /Загрузки
Потоковая либерация отсюда: https: // www.Ардуино.cc/en/reference/библиотеки
Оборудование STM32 для IDE из репо Стивестронга: https: // github.com/stevstrong/arduino_stm32
LiveOV7670 из репо Стивестронга: https: // github.com/stevstrong/liveov7670_stm32
С небольшим изменением кода для смены распинной аутир: instead: Adafruit_ILI9341_STM tft(PA4, PA3, PA2); // SS, DC, RST I got Adafruit_ILI9341_STM tft(PA2, PA0, PB4); // SS, DC, RST

Стивестронг
Пт 18 августа 2017 г., 7:42
Если вы используете более старую версию ILI9341, вы нарушаете одно основное правило для чтения пикселей, потому что вы будете переключать CS (сделано в рамках функции writeCommand ()).
Моя новая версия с переработанной CS и DC PIN -комбинезом сделает это правильно.

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

Rogerclark
Пт 18 августа 2017 г., 7:45 утра
Я не знаю, имеет ли это какое -либо значение, но вы не должны заменить компилятор новой версией, если использует Libmaple

Просто используйте компилятор, который установлен с помощью IDE

Примечание. Я думаю, что Core STM может потребовать более новой версии компилятора, но если вам нужно использовать ядро ​​Libmaple и STM, вам нужно будет управлять тем, как вы обрабатываете 2 разные версии компилятора, чтобы каждое ядро ​​использовало правильную версию

Концзакп
Ср 30 августа 2017 г. 12:15
Стив, ты уже вернулся домой? Если да, то вы бы собрали для меня еще раз бинар в вашей среде, но с этим изменением булавок ? Adafruit_ILI9341_STM tft(PA2, PA0, PB4); // SS, DC, RST

Стивестронг
Сб 02 сентября 2017 г. 8:56 утра
Хорошо, я выяснил, почему PB4 не работает: он был установлен в качестве ввода в настройке камеры.
Теперь это работает правильно. Я поступил на Guthub на GitHub.

Прикрепил файл корзины в соответствии с вашим закреплением: Adafruit_ILI9341_STM tft(PA2, PA0, PB4); // SS, DC, RST

Концзакп
Сб 02 сентября 2017 г., 19:23
Есть некоторый прогресс ... У меня есть видео, не проходя белый экран, но оно не выглядит хорошо. Вот моя расписка: Camera connection: PA8 - XCLK PB3 - HREF PA1 - PCLK PB5 - VSYNC PB6 - SIDC via 10k PB7 - SIDO via 10k PB8..PB15 - D0..D7 3.3v - Reset PWDN - GND

Стивестронг
Солнце 03 сентября 2017 г. 7:37 утра
Я построил двоичный файл со следующими подключениями: // TFT connection: // PB4 - TFT reset // PA0 - TFT D/C (data/command) // PA2 - TFT chip select // PA5 - TFT SPI CLK // PA6 - TFT SPI MISO // PA7 - TFT SPI MOSI // Camera connection: // PA8 - camera clock // PB3 - HREF // PA1 - pixel clock PCLK // PB5 - VSYNC // PB6 - I2C Clock (2k7) // PB7 - I2C data (2k7) // PB8..PB15 - pixel data

Rogerclark
Солнце 03 сентября 2017 г. 7:42 утра
Стив,

Прекрасно работает для меня.

Я вытащил последнюю версию библиотеки, и единственное, что я изменил, - это булавки TFT, так как я припаял их на немного разных булавках
Adafruit_ILI9341_STM tft = Adafruit_ILI9341_STM(PA2, PA0, PA3);

Стивестронг
Солнце 03, 2017 7:52 утра
Позвольте знать, что некоторым еще также удалось заставить его работать. :)

Rogerclark
Солнце 03 сентября 2017 г. 10:20 утра
[Стивестронг - Солнце 03 сентября 2017 г. 7:52 утра] - Позвольте знать, что некоторым еще также удалось заставить его работать. :)
Не беспокойся

Я думаю, что @konczakp либо неправильно подключил камеру, либо имеет какую -то оборудование.

КСТАТИ. Я полагаю, что у Концзакпа есть резисторы подтягивания на соединениях I2C с камерой.

Концзакп
Солнце 03 сентября 2017 г. 11:50 утра
Стивестронг написал: Вы получаете полное сообщение на ЖК -дисплее?

ZMEMW16
Солнце 03 сентября 2017 г. 15:52
3K3 3V3
4K7 5V0
кажется наиболее распространенным в использовании, которые я видел
Вы округлые углы / края на сигналах, эффект RC??

SRP
Google 'Влияние нагрузочных резисторов на i2c'

https: // www.Google.сопутствующий.Великобритания/URL?SA = T&rct = j ... Abtyfs_ojw

PDF
https: // www.Google.сопутствующий.Великобритания/URL?SA = T&rct = j ... 4_72vipqcg

Стивестронг
Солнце 03 сентября 2017 г. 15:53
Я использовал резисторы 2K7, на высокой скорости необходимо это небольшое значение.
Я бы попробовал по крайней мере 4K7, в любом случае 10K - это слишком много.

Концзакп
Солнце 03 сентября 2017 г., 19:39
Я только что попробовал 2K4 (не было 2K7), но никаких изменений:/

Rogerclark
Солнце 03 сентября 2017 г. 9:45 вечера
Похоже, у вас есть проблема с одним из битов данных камеры.

У меня изначально была проблема с сухим соединением на одной булавке.

Rogerclark
Солнце 03 сентября 2017 г. 9:48 вечера
Стив...

В настоящее время вы используете PA1 для пиксельных часов, но я не вижу, как его изменить.

Какие другие контакты могут быть использованы (с соответствующими изменениями в коде таймера и DMA) ?

Rogerclark
Солнце 03 сентября 2017 22:14
Я говорил слишком рано, когда сказал, что это работает нормально для меня

Я только что включил свой главный компьютер, в котором есть чертежи, камера и т. Д

Итак, я ездил на велосипеде, а затем получил лучшую цветную картину, но очень низкая частота кадров.

Интересно, связана ли эта проблема с настройкой i2c.

Я проверил и использую 4.7k подтягивания, что, вероятно, слишком высокое.


Я не вспоминаю эту проблему со старой версией библиотеки Стива, и я думаю, что у меня может быть резервная копия этого, поэтому я посмотрю, смогу ли я вернуться к тому, что я использовал ранее

В качестве альтернативы, проблема может быть чем -то связанным с Wire Lib, так как мы сейчас используем аппаратный i2c по умолчанию - но она для меня работает с оборудованием i2c

Rogerclark
Солнце 03 сентября 2017 22:19
Обновлять.

Предыдущая версия библиотеки Стива кажется более стабильной

Я вернулся к использованию старой версии, и она сразу же сработала.

@Стив

Что ты изменил ??? (Думаю, я могу посмотреть на GitHub или запустить мульти -файл Diff в коде)

Rogerclark
Солнце 03 сентября 2017 11:06
Мммм

Довольно много изменений между двумя версиями, которые у меня есть.

Существуют изменения в настройке регистров, а также на различных вещах, поэтому очень трудно понять, какое изменение вызывает камеру теперь не генерирует хорошее видео большую часть времени.

Rogerclark
Пн сентября 04, 2017 7:46 утра
Я пытаюсь отследить, в чем проблема, и я думаю, что это потенциально неонициализированные булавки

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

Но, как это случайно, независимо от того, работает или нет, трудно понять, исправило ли конкретное изменение или нет

Я вижу, что Стив изменил код инициализации, чтобы он устанавливал регистр управления аппаратным управлением непосредственно с 0x44444444, который устанавливает биты данных камеры на вход.

Но более старый код также устанавливает PinMode для PB3, PB4 и PB5

На моей плате PB3, PB5, PB7 и PB7 используются, так что, возможно, один из них не инициализируется ??

Определенно что -то не инициализировано


Пса. Кто -нибудь знает, почему, если я коснусь контактов с данными камеры (я не уверен, что это биты данных или VSYNC HSYNC и т. Д.), Что камера соходит с ума, и у меня половина изображения ?

Мне трудно поверить, что статическое от моих пальцев делает, но, возможно, это емкость моих пальцев ?

Rogerclark
Пн сентября 04, 2017 8:26 утра
Re: Моя проблема с прикосновением к булавкам, вызывая проблему

Это потому, что я не вытащил сброс высоко

Я теперь вытащил сброс до 3.3 через 1k и pwdn low через 1K. Это останавливает проблемы, вызванные при прикосновении к сбросу штифта

К сожалению, проблема с перерывами камеры не работает.

Я также посмотрел на все версии, которые Стив начал с GitHub, и у них у всех есть такая же проблема

Единственная стабильная версия - это версия, которую он разместил здесь как Zip.

Концзакп
Пн сентября 04, 2017 8:35 утра
В некотором смысле хорошо слышать, что проблема не только с моей установкой ... Потому что я просто хотел сегодня распутать все и вернуться к макетинге :рулон: Если только одна версия работает правильно (Zip, размещенная в этой теме), то кажется, что чтение и все, что связано с ним, может привести к этому?

Rogerclark
Пн сентября 04, 2017 8:40
Я не думаю, что это чтение

Я все еще пытаюсь отследить, в чем проблема, но старый код, у которого есть строка настройки
BufferedCameraOV7670_QVGA camera(CameraOV7670::PIXEL_RGB565, BufferedCameraOV7670_QVGA::FPS_11p_Hz);

Стивестронг
Пн сентября 04, 2017 8:44
Роджер, когда вы говорите о стабильной версии, вы имеете в виду ZIP -файл из этого поста: http: // www.STM32duino.com/viewtopic.PHP ... 230#P32495 ?
Частота кадров отличается для последней и прикрепленной версии.
Прикрепленная версия имеет 11 кадров в секунду, последняя имеет 15 кадров в секунду, и это очень важно, это абсолютный предел.
Вы можете попробовать более низкие FPS, используя более высокое значение прекалера, например, 6 вместо 5.

OTOH сигнал I2C чист, а края в порядке (я использую резисторы 2K7), поэтому я предполагаю, что инициатор камеры всегда выполняется правильно.

Rogerclark
Пн сентября 04, 2017 10:36 утра
Стив

Я использую 4.7K подтягивания, которые работают в порядке с вашей старой версией, поэтому я не думаю, что это проблема, если вы не изменили что -то в коде провода ??

Я предполагаю, что старая версия, которая у меня есть, должна быть из опубликованного вами файла Zip, потому что она предварительно датируется кодом, который в вашем репозитории GitHub


Re: Изменение значения предварительного скалера на 6
BufferedCameraOV7670_QVGA camera(CameraOV7670::PIXEL_RGB565, (BufferedCameraOV7670_QVGA::Prescaler)6);

Rogerclark
Пн сентября 04, 2017 22:36
Стив

Я попробовал снова сегодня утром, и даже с другим предварительным шкалером он не работает, когда доска холодно (10 градусов)

Можете ли вы попробовать поместить свою доску (включая камеру) в холодильник и попробуйте еще раз
(Пс. Вам, вероятно, нужно поместить все это в полиэтиленовый пакет, и просто выпустите кабель из сумки, иначе, когда вы вытащите его из холодильника, он получит много конденсации на доске)

Пса. Я постараюсь изменить подтягивания i2c на более низкое значение и посмотрю, исправляет ли это, но когда старый код работает, когда доска холодно, я не вижу, как это может быть проблемой.

Редактировать

Я заменил резисторы I2C на 2.7k, но это не имело никакого значения

Я поместил всю свою тестовую настройку (BP+Camera+Display) в пластиковый пакет и положил в холодильник, и когда я снова вытащил их, у меня возникает проблема, когда светодиод вообще не мигает, чтобы указать, что его получение импульсов рамы

Когда он согревается, я получаю видео, но все цвета неверны

Старый код (из файла ZIP) всегда работает, даже когда плата холодно.

Стивестронг
Вторник 05 сентября 2017 г. 8:40
Хм, кажется, что ШИМ не запускается, поэтому не будет создан PCLK.
У меня также есть проблема неправильных цветов в ~ 1 из 5 стартов.
Я должен посмотреть на это. В настоящее время отсутствует только время...

Rogerclark
Вторник 05 сентября 2017 г. 10:52 утра
Стив

Не беспокойся

Я счастлив, используя старую версию.

Я могу постепенно попытаться интегрировать некоторые изменения из вашей последней версии, но у меня тоже не так много времени на это ;-)

Концзакп
Чт, 07 сентября 2017 г., 11:52
К сожалению, я не мог работать даже над более старой версией, поэтому я решил все непромочить и вернуться к макете. Во время падения я повредил один из штифтов камеры, и я не могу отследить, какой из них. Итак, я только что заказал новый. Надеюсь получить это быстро .... :плакать:

Rogerclark
Солнце 10 сентября 2017 г., 7:20 утра
К вашему сведению

В настоящее время я пытаюсь разработать печатную плату, у которой будет Bluepill ILI9341 2.4 -дюймовый дисплей и камера OV7670
BluePillDisplay.PDF
(43.73 киб) скачано 22 раза

Rogerclark
Чт 14 сентября 2017 г. 12:08
Возможно, есть ошибки, но я сделал первый проход на печатной плате
bp_camera_pcb.png
bp_camera_pcb.PNG (55.66 киб) просмотрено 322 раза

Rogerclark
Пт 22 сентября 2017 г. 7:25 утра
Работая над сохранением изображения на SD -карту, мне удалось сохранить один из экранов от эскиза GraphicStest в SD

Я не уверен, что технически это должно работать или нет, потому что я делюсь автобусом SPI как с SD -картой, так и с ЖК -дисплее.

Lcd_to_sd_test1.png
Lcd_to_sd_test1.PNG (2.61 киб) просмотрено 267 раз

Rogerclark
Пт 22 сентября 2017 г. 8:09 утра
Только что прошел некоторые скоростные тесты и 1000 вызовов для чтения
unsigned long m=millis(); for(int i=0;i<1000;i++) { tft.readPixels(0,0,320,0, lineBufLCD); } Serial.println(millis()-m);

Стивестронг
Пт 22 сентября 2017 12:29
Просто для записи, вот пример, как написать BMP: http: // форум.Ардуино.CC/INDEX.PHP?тема ... #msg849962

и хороший энкодер JPEG (для STM32L1): https: // github.com/mitchd/vt-fox-1/дерево ... de/encoder

Rogerclark
Пт 22 сентября 2017 г., 8:19 вечера
Спасибо, Стив

Я уже использую фрагменты, а не код BMP с форума Arduno, и, кажется, работает нормально.

Спасибо за ссылку на компрессор L1 Joeg, ​​но для F1 я не уверен, достаточно ли у него ОЗУ.

Написание в SD в настоящее время очень медленно, если я пишу только 1 строку за раз. (более 5 секунд)

Я должен быть в состоянии писать по 12 строк за раз, или, возможно, даже 15 строк, но я еще не сделал эту работу.

Мои первоначальные расчеты заключались в том, что я мог бы написать дисплей 320x240 на SD примерно на 400 мс, но я не учитывал довольно медленную скорость переноса в SD, когда составляет всего несколько сотен килограммов в секунду в секунду.
Поэтому я думаю, что время для написания SD, вероятно, будет около 900 мс или, возможно, в лучшем случае 800 мс.

Rogerclark
Пт 22 сентября 2017 г. 22:07
Написав 12 строк за раз, у меня есть время до 742 мс

Я все еще читаю дисплей, линию за линейностью, поэтому я, вероятно, могу сбрить несколько MS от этого, но хотя чтение с ЖК -дисплее в коде (в блоках по 12 строк за раз)

КСТАТИ.
Это возвращается к моей первой работе, когда я работал над обработкой изображений с высоким разрешением для индустрии печати, в те дни, прежде чем изображение 50 МБ можно было легко обработать с помощью RPI $ 10 RPI ;-)

Редактировать

Я провел несколько испытаний на время, и чтение нескольких строк из ЖК -дисплее

Время прочитать 240 строк индивидуально из ЖК -дисплея будет 116.64 мс
Время прочитать 240 строк в блоках 10 из ЖК -дисплея будет 104.13 мс

Однако, если я прочитаю 10 строк с дисплея, буфер линии (ы) необходимо обработать, чтобы обмениваться порядок линии, и это добавит небольшое количество времени к общему количеству.

Это, вероятно, было бы немного быстрее сделать это, но это будет менее 10 мс в общее время около 700 мс, поэтому на данный момент я не думаю, что это стоит времени, чтобы заставить его работать !

Пса. Я также попытался изменить параметры окна на то, что направление окна y окна было -1 e.глин. Строки с 239 до 230, а не от 230 до 239
Тем не менее, это, казалось, привело к повреждению данных об изображении
(Обратите внимание, что мне нужно повторить это, так как у меня также возникают проблемы с SPI, когда я пытаюсь перенести более 11 строк за раз, поэтому я не могу исключить, что быть проблемой, а не перевернутой проблемой окна изображения)

Rogerclark
Сб 23 сентября 2017 г. 12:13
Я просто дважды проверил, может ли чткий защитник иметь ystart > Йенд, но это определенно вызывает коррупцию данных

Я собираюсь вернуться к чтению LCD -линии по линии, так как я не думаю, что это сэкономит какое -либо значительное время, прочитав несколько линий из -за времени, чтобы обмениваться линиями, я.E Потребуется 3 вызова MEMCPY на пару линий, которые заменены, и ей потребуется дополнительная линия буферизации, которая не может быть использована для передачи SD -карты

victor_pv
Сб 23 сентября 2017 г. 2:56 утра
Роджер, насколько велики буферы, которые вы читаете с камеры, и насколько велик тот, который вы пишете для SDCARD?

Я спрашиваю, потому что мне повезло, запустив SDFAT параллельно с другими вещами с модифицированным драйвером, который использует новые функции обратного вызова DMA, и Freertos.
Очевидно, что если буферы невелики, нет большой прироста, поскольку RTOS должен переключать задачи, и это тратит впустую циклы процессора, но если буферы достаточно велики, скажем, немного KB, вы можете делать больше вещей параллельно, Возможно, прочитайте строки с камеры и напишите на карту только время, занимая время самого длинного, в то время как другой запускается в фоновом режиме, используя время ЦП, которое будет потрачено впустую.
Это очень похоже на то, что вы делали с асинхронной функцией со светодиодами, но, поскольку есть обратные вызовы, нет необходимости проверять, закончились ли DMA, драйвер SPI просто вызовет соответствующий ISR, когда они.

Это мой случай - это просто доказательство концепции с игроком WAV, и делает так:
Задача 1 считывается из SDCARD и устанавливает данные в качестве буфера для другого другого канала DMA для вывода на таймеры.
Задача 2 записывает некоторые статистики на экране (в основном использование ЦП).
Задача 3 просто рисует куб, чтобы что -то сделать со временем процессора.
Некоторые процедуры прерывания переключения буферов.

Таким образом, когда задача 1 была до «блокировки» в чтении SDFAT, она больше не блокирует и вместо этого выполняет переключатель задачи на задачу 2 или 3, в зависимости от того, что готово к выполнению.
Когда SPI DMA завершает вызовы новой ISR, который сообщает RTOS задачу SDFAT, Task1, готов к выполнению, а RTOS делает переключатель обратно к этой задаче.
Поскольку это управляется в рамках кода драйвера SDFAT SPI, он совместим с чем -либо, другие задачи не должны иметь никаких изменений, они просто получают чаще чаще.
Я забыл, сколько времени процессора я мог видеть, сохранившись таким образом, но это было несколько %, и мой код просто читает с машины, пишет еще больше времени, так что может принести пользу больше.
Вы можете использовать одни и те же методы для записи на карту, так и для чтения с камеры, поэтому, хотя оба переноса идут параллельно, любой код должен работать в процессоре, может работать.

Rogerclark
Сб 23 сентября 2017 г. 3:52
Привет, Виктор

И камера, и SD находятся на одной шине SPI (SPI1)
Я не могу использовать SPI2, потому что камера должна быть на определенных булавках I.E PB8 - PB15 как код Стива делает чтение DMA из верхней половины порта B.
(И вот где находится SPI 2)

Мне нужно было проверить, можно ли перебрать SPI2, но у меня очень мало не используемых контактов, поэтому в цепи есть невозможны, так как есть другие булавки, которые не могут быть изменены, потому что таймеры, которые они ассоциируются с.

Меня не беспокоит, если для сохранения в SD требуется 750 мс, это просто странно, что я внезапно получу замедление, если я использую буфер с 12 линейками, когда буфер 11 в порядке.

Rogerclark
Сб 23 сентября 2017 г., 4:54
Стив

Я попытался сохранить ЖК -дисплей после того, как с камеры прочитал кадр, но он не удается, потому что выглядит так, как таймер, DMA и т. Д.

Вот мой код, который я использую для чтения дисплея и написать в SD
#include #include "Adafruit_ILI9341_STM.h" #define TFT_CS PB0 #define TFT_DC PA2 #define TFT_RST PB1 Adafruit_ILI9341_STM tft = Adafruit_ILI9341_STM(TFT_CS, TFT_DC, TFT_RST); // Use hardware SPI const uint8_t SD_CS = PC15; SdFat sd; unsigned long testText() { tft.fillScreen(ILI9341_BLACK); tft.setCursor(0, 0); tft.setTextColor(ILI9341_RED); tft.setTextSize(3); tft.println("LCD Screen reader\n"); tft.setTextColor(ILI9341_GREEN); tft.setTextSize(3); tft.println("rogerclark.net\n"); tft.setTextColor(ILI9341_BLUE); tft.setTextSize(3); tft.println(__TIME__); tft.setTextSize(2); return 0; } void LCD2SD() { const int w = 320; const int h = 240; SdFile file; #define NUM_LINES_BUFFERED 12 uint8_t lineBufSD[w*3*NUM_LINES_BUFFERED]; unsigned char bmpFileHeader[14] = {'B', 'M', 0, 0, 0, 0, 0, 0, 0, 0, 54, 0, 0, 0 }; unsigned char bmpInfoHeader[40] = {40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 24, 0 }; unsigned long m; char name[] = "LCD_00.bmp"; // if name exists, create new filename for (int i = 0; i < 100; i++) { name[4] = i / 10 + '0'; name[5] = i % 10 + '0'; if (file.open(name, O_CREAT | O_EXCL | O_WRITE)) { break; } } // create image data int filesize = 54 + 4 * w * h; // w is image width, h is image height bmpFileHeader[ 2] = (unsigned char)(filesize ); bmpFileHeader[ 3] = (unsigned char)(filesize >> 8); bmpFileHeader[ 4] = (unsigned char)(filesize >> 16); bmpFileHeader[ 5] = (unsigned char)(filesize >> 24); bmpInfoHeader[ 4] = (unsigned char)( w ); bmpInfoHeader[ 5] = (unsigned char)( w >> 8); bmpInfoHeader[ 6] = (unsigned char)( w >> 16); bmpInfoHeader[ 7] = (unsigned char)( w >> 24); bmpInfoHeader[ 8] = (unsigned char)( h ); bmpInfoHeader[ 9] = (unsigned char)( h >> 8); bmpInfoHeader[10] = (unsigned char)( h >> 16); bmpInfoHeader[11] = (unsigned char)( h >> 24); file.write(bmpFileHeader, sizeof(bmpFileHeader)); // write file header file.write(bmpInfoHeader, sizeof(bmpInfoHeader)); // " info header m=millis(); uint8_t t; int lineOffset; for (int y = 0 ; y < h ; y++) { lineOffset = y%NUM_LINES_BUFFERED *3 * w; tft.readPixels24(0,(h-1)-y,320,(h-1)-y, lineBufSD + lineOffset); if ((y+1)%NUM_LINES_BUFFERED==0) { // swap colour channels from RGB to BGR for (int x = 0; x < w * 3 * NUM_LINES_BUFFERED; x+=3) { t=lineBufSD[x+2]; lineBufSD[x+2]=lineBufSD[x]; lineBufSD[x]=t; } file.write(lineBufSD, 3 * w * NUM_LINES_BUFFERED); } } Serial.print("Saved in ");Serial.print(millis()-m);Serial.println(" mS "); file.close(); } void setup() { Serial.begin(9600); delay(500); Serial.println("Starting"); if (!sd.begin(SD_CS, SD_SCK_MHZ(50))) { sd.initErrorHalt(); } tft.begin(); uint16_t screen_w = ILI9341_TFTHEIGHT; uint16_t screen_h = ILI9341_TFTWIDTH; tft.setRotation(1); testText();// Draw something // tft.setAddrWindow(0, 0, screen_w, screen_h); // tft.setCursor(0, 0); LCD2SD(); } void loop() { }

Rogerclark
Сб 23 сентября 2017 г. 5:20 утра
Еще одно обновление.

Похоже на код настройки таймера в коде LiveOV7670
void TIMER_Setup(void) { gpio_set_mode(GPIOA, 1, GPIO_INPUT_FLOATING); // Slave mode: Reset mode (see RM0008, chap. 15.3.14, page 394) // ------------------------ // The counter and its prescaler can be reinitialized in response to an event on a trigger input. // Moreover, if the URS bit from the TIMx_CR1 register is low, an update event UEV is generated. // Then all the preloaded registers (TIMx_ARR, TIMx_CCRx) are updated. // // In the following example, the upcounter is cleared in response to a rising edge on TI2 input: // • Configure the channel 2 to detect rising edges on TI2. // - Configure the input filter duration (in this example, we don’t need any filter, so we keep IC1F=0000). // - The capture prescaler is not used for triggering, so you don’t need to configure it. // - The CC2S bits select the input capture source only, CC2S = 01 in the TIMx_CCMR1 register. // - Write CC2P=0 in TIMx_CCER register to validate the polarity (and detect rising edges only). // • Configure the timer in reset mode by writing SMS=100 in TIMx_SMCR register. // - Select TI2 as the input source by writing TS=101 in TIMx_SMCR register. // • Start the counter by writing CEN=1 in the TIMx_CR1 register. // // The counter starts counting on the internal clock, then behaves normally until TI2 rising edge. // When TI2 rises, the counter is cleared and restarts from 0. // In the meantime, the trigger flag is set (TIF bit in the TIMx_SR register) and an interrupt request, // or a DMA request can be sent if enabled (depending on the TIE and TDE bits in TIMx_DIER register). // // This event will trigger the DMA to save the content of GPIOB.IDR[1] to memory. timer_pause(TIMER2); // stop timer timer_init(TIMER2); // turn timer RCC on // configure PA2 = timer 2 channel 2 == input TI2 #define TIMER_RELOAD_VALUE 2 // must be adapted according to the results // as this mode is not supported by the core lib, we have to set up the registers manually. //(TIMER2->regs).gen->CR1 = TIMER_CR1_CEN; (TIMER2->regs).gen->CR2 = 0; (TIMER2->regs).gen->SMCR = (TIMER_SMCR_TS_TI2FP2 | TIMER_SMCR_SMS_RESET);//TIMER_SMCR_SMS_TRIGGER); (TIMER2->regs).gen->DIER = (TIMER_DIER_UDE); // enable DMA request on TIM2 update (TIMER2->regs).gen->SR = 0; (TIMER2->regs).gen->EGR = 0; (TIMER2->regs).gen->CCMR1 = TIMER_CCMR1_CC2S_INPUT_TI2; // IC2F='0000', IC2PSC='0', CC2S='01' (TIMER2->regs).gen->CCMR2 = 0; (TIMER2->regs).gen->CCER = (TIMER_CCER_CC2P); // inverse polarity, active low (TIMER2->regs).gen->CNT = 0;//TIMER_RELOAD_VALUE; // set it only in down-counting more (TIMER2->regs).gen->PSC = 0; (TIMER2->regs).gen->ARR = 0;//TIMER_RELOAD_VALUE; (TIMER2->regs).gen->CCR1 = 0; (TIMER2->regs).gen->CCR2 = 0; (TIMER2->regs).gen->CCR3 = 0; (TIMER2->regs).gen->CCR4 = 0; (TIMER2->regs).gen->DCR = 0; // don't need DMA for timer (TIMER2->regs).gen->DMAR = 0; // don't forget to set the DMA trigger source to TIM2-UP //timer_resume(TIMER2); // start timer }

Rogerclark
Сб 23 сентября 2017 г. 6:56 утра
Я приближаюсь к решению.

Проблема такова

(Таймер2->регс).генерал->Dier = (timer_dier_ude); // включить запрос DMA в обновлении TIM2

Кажется, каким -то образом мешает SDFAT

Если я отключу DMA в обновлении TIM2, я могу сохранить изображение в SD.
(TIMER2->regs).gen->DIER = (0); // disable DMA request on TIM2 update

Стивестронг
Сб 23 сентября 2017 г. 8:30 утра
Роджер, вы должны сначала остановить таймер, прежде чем написать SD. Таким образом, таймер DMA, даже если он включен, не будет активирован.
После написания на SD Card просто возобновите таймер (XCLK).

РЕДАКТИРОВАТЬ1
Ах, я думаю, что чтение пикселей не будет работать, если XCLK остановлен.
В этом случае следует временно деактивировать таймер DMA или сам канал DMA.
И возобновить его после написания SD -карты.

Edit2
Я признаю, что странно, что таймер DMA вступает в конфликт со SPI DMA.
Я думаю, что Виктор провел всестороннее исследование того, что происходит, когда SPI 1 и 2 проходят параллельно (с DMA). Я думаю, что он пришел к выводу, что они противоречивы, когда SPI 1 работает с 36 МГц, некоторые байты данных спорадически потеряны.

Rogerclark
Сб 23 сентября 2017 г. 8:37
Я пытался использовать Timer_pause (Timer2); Но это не помогло

Мне пришлось отключить DMA

(Таймер2->регс).генерал->Dier = (0); // Отключить запрос DMA в обновлении TIM2

Стивестронг
Сб 23 сентября 2017 г. 8:40
Странно, это означает, что DMA запускается, даже если таймер остановлен?
Хм.

Rogerclark
Сб 23 сентября 2017 г. 8:47
Да.

Просто запустив первую часть кода в timer_setup ()
void TIMER_Setup(void) { gpio_set_mode(GPIOA, 1, GPIO_INPUT_FLOATING); timer_pause(TIMER2); // stop timer timer_init(TIMER2); // turn timer RCC on #define TIMER_RELOAD_VALUE 2 // must be adapted according to the results // as this mode is not supported by the core lib, we have to set up the registers manually. //(TIMER2->regs).gen->CR1 = TIMER_CR1_CEN; (TIMER2->regs).gen->CR2 = 0; (TIMER2->regs).gen->SMCR = (TIMER_SMCR_TS_TI2FP2 | TIMER_SMCR_SMS_RESET);//TIMER_SMCR_SMS_TRIGGER); (TIMER2->regs).gen->DIER = (TIMER_DIER_UDE); // enable DMA request on TIM2 update

Стивестронг
Сб 23 сентября 2017 г. 9:00 утра
После получения полной линии от камеры, прежде чем записать данные в ЖК -дисплей, я делаю: timer_pause(TIMER2); // stop timer dma_disable(DMA1, DMA_CH2); dma_clear_isr_bits(DMA1, DMA_CH2);

Rogerclark
Сб 23 сентября 2017 г. 9:03
ХОРОШО

Я попробую это

КСТАТИ.
В настоящее время после написания в SD, только что повторное определение таймера DMA включает в себя, не запускает камеру снова, но если мне придется полностью повторно вводить таймер, DMA и т. Д. так как это занимает около 700 мс

Стивестронг
Сб 23 сентября 2017 г. 9:09
Вы можете попытаться оставить настройки таймера, просто отключить канал DMA //timer_pause(TIMER2); // stop timer dma_disable(DMA1, DMA_CH2); dma_clear_isr_bits(DMA1, DMA_CH2);

Rogerclark
Сб 23 сентября 2017 г. 10:49
Привет, Стив

Я не понимаю, почему, но звонит
dma_disable(DMA1, DMA_CH2); dma_clear_isr_bits(DMA1, DMA_CH2);

Стивестронг
Солнце 24 сентября 2017 г. 8:32
Я подключил SD -карту, снял резисторы, Sdinfo работает, поэтому я скоро проверю ваш эскиз.
Где определенный readpixels24 ()? Я думаю, что он должен читать и хранить 4 байта вместо 3, потому что, насколько я знаю, данные о пикселях BMP должны быть 4 байта выровнены.

Rogerclark
Солнце 24 сентября 2017 г. 8:37
uint16_t Adafruit_ILI9341_STM::readPixels24(int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint8_t *buf) { mSPI.beginTransaction(SPISettings(_safe_freq, MSBFIRST, SPI_MODE0, DATA_SIZE_8BIT)); writecommand(ILI9341_CASET); // Column addr set spiwrite16(x1); spiwrite16(x2); writecommand(ILI9341_PASET); // Row addr set spiwrite16(y1); spiwrite16(y2); writecommand(ILI9341_RAMRD); // read GRAM (void)spiread(); //dummy read uint8_t r, g, b; uint16_t len = (x2-x1+1)*(y2-y1+1); uint16_t ret = len; mSPI.dmaTransfer(buf, buf, len*3); cs_set(); mSPI.beginTransaction(SPISettings(_freq, MSBFIRST, SPI_MODE0, DATA_SIZE_16BIT)); return ret; }

Rogerclark
Солнце 24 сентября 2017 г. 9:55 утра
КСТАТИ.

У меня это так, как это
lcd_sd_camera_blue_pill.png
lcd_sd_camera_blue_pill.PNG (31.55 киб) просмотрено 712 раз

Rogerclark
Солнце 24 сентября 2017 г. 10:08
Нашел 1 проблему.


Похоже, SD оставьте SPI в 8 -битном режиме, но ILI9341 LIB нуждается в 16 -битном режиме

Поэтому я добавил звонок, чтобы установить в 16 бит, прежде чем написать текст в ЖК -дисплей, и теперь он сохраняет ЖК -экран несколько раз
#include #include "Adafruit_ILI9341_STM.h" #define TFT_CS PB0 #define TFT_DC PA2 #define TFT_RST PB1 Adafruit_ILI9341_STM tft = Adafruit_ILI9341_STM(TFT_CS, TFT_DC, TFT_RST); // Use hardware SPI const uint8_t SD_CS = PC15; SdFat sd; unsigned long testText() { SPI.setDataSize(DATA_SIZE_16BIT); tft.fillScreen(ILI9341_BLACK); tft.setCursor(0, 0); tft.setTextColor(ILI9341_RED); tft.setTextSize(3); tft.println("LCD Screen reader\n"); tft.setTextColor(ILI9341_GREEN); tft.setTextSize(3); tft.println("rogerclark.net\n"); tft.setTextColor(ILI9341_BLUE); tft.setTextSize(3); tft.println(__TIME__); tft.println(random(100000)); return 0; } void LCD2SD() { const int w = 320; const int h = 240; SdFile file; #define NUM_LINES_BUFFERED 12 uint8_t lineBufSD[w * 3 * NUM_LINES_BUFFERED]; boolean doFileActions = true; unsigned char bmpFileHeader[14] = {'B', 'M', 0, 0, 0, 0, 0, 0, 0, 0, 54, 0, 0, 0 }; unsigned char bmpInfoHeader[40] = {40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 24, 0 }; unsigned long m; char name[] = "LCD_00.bmp"; if (doFileActions) { // if name exists, create new filename for (int i = 0; i < 100; i++) { name[4] = i / 10 + '0'; name[5] = i % 10 + '0'; if (file.open(name, O_CREAT | O_EXCL | O_WRITE)) { break; } } } // create image data int filesize = 54 + 4 * w * h; // w is image width, h is image height bmpFileHeader[ 2] = (unsigned char)(filesize ); bmpFileHeader[ 3] = (unsigned char)(filesize >> 8); bmpFileHeader[ 4] = (unsigned char)(filesize >> 16); bmpFileHeader[ 5] = (unsigned char)(filesize >> 24); bmpInfoHeader[ 4] = (unsigned char)( w ); bmpInfoHeader[ 5] = (unsigned char)( w >> 8); bmpInfoHeader[ 6] = (unsigned char)( w >> 16); bmpInfoHeader[ 7] = (unsigned char)( w >> 24); bmpInfoHeader[ 8] = (unsigned char)( h ); bmpInfoHeader[ 9] = (unsigned char)( h >> 8); bmpInfoHeader[10] = (unsigned char)( h >> 16); bmpInfoHeader[11] = (unsigned char)( h >> 24); if (doFileActions) { file.write(bmpFileHeader, sizeof(bmpFileHeader)); // write file header file.write(bmpInfoHeader, sizeof(bmpInfoHeader)); // " info header } m = millis(); uint8_t t; int lineOffset; for (int y = 0 ; y < h ; y++) { lineOffset = y % NUM_LINES_BUFFERED * 3 * w; tft.readPixels24(0, (h - 1) - y, 320, (h - 1) - y, lineBufSD + lineOffset); if ((y + 1) % NUM_LINES_BUFFERED == 0) { // swap colour channels from RGB to BGR for (int x = 0; x < w * 3 * NUM_LINES_BUFFERED; x += 3) { t = lineBufSD[x + 2]; lineBufSD[x + 2] = lineBufSD[x]; lineBufSD[x] = t; } if (doFileActions) { file.write(lineBufSD, 3 * w * NUM_LINES_BUFFERED); } } } Serial.print("Saved in "); Serial.print(millis() - m); Serial.println(" mS "); if (doFileActions) { file.close(); } } void setup() { Serial.begin(9600); delay(500); Serial.println("Starting"); if (!sd.begin(SD_CS, SD_SCK_MHZ(50))) { sd.initErrorHalt(); } tft.begin(); uint16_t screen_w = ILI9341_TFTHEIGHT; uint16_t screen_h = ILI9341_TFTWIDTH; tft.setRotation(1); } void loop() { testText();// Draw something LCD2SD(); delay(1000); }

Rogerclark
Солнце 24 сентября 2017 г. 10:24
КСТАТИ.

Чтобы заставить SD работать, я удалил резисторы, а также сократил ссылку рядом с 3.3V регулятор на ЖК -плате, так что SD -карта получает 3.3 В вместо 3 В

Я не уверен, нужно ли мне сделать что -нибудь из этого, но SD работает для меня.

Rogerclark
Солнце 24 сентября 2017 г. 10:42
Стив

У меня это как -то работает
// // Created by indrek on 4.12.2016. // // Adapted for ILI9341 by stevestrong on 29.07.2017 // #include #include #include const uint8_t SD_CS = PC15; SdFat sd; // TFT connection: // PB1 - TFT reset // PA2 - TFT D/C (data/command) // PB0 - TFT chip select // PA5 - TFT SPI CLK // PA6 - TFT SPI MISO // PA7 - TFT SPI MOSI // Camera connection: // PA8 - camera clock // PB3 - HREF // PA1 - pixel clock PCLK // PB5 - VSYNC // PB6 - I2C Clock // PB7 - I2C data // PB8..PB15 - pixel data // CPU@72MHZ -> 11fps, CPU@80MHZ-> 12.5fps BufferedCameraOV7670_QVGA camera(CameraOV7670::PIXEL_RGB565, BufferedCameraOV7670_QVGA::FPS_11p_Hz); #define LED_PIN PC13 #define TFT_CS PB0 #define TFT_DC PA2 #define TFT_RST PB1 Adafruit_ILI9341_STM tft = Adafruit_ILI9341_STM(TFT_CS, TFT_DC, TFT_RST); // Use hardware SPI #define SD_CS PC15 // Normally it is a portrait screen. Use it as landscape uint16_t screen_w = ILI9341_TFTHEIGHT; uint16_t screen_h = ILI9341_TFTWIDTH; uint16_t screenLineIndex; uint8_t bufIndex; #define PIXELS_PER_LINE ILI9341_TFTHEIGHT // The GPIO.IDR register can be only accessed in word (32 bit) mode. // Therefore a 4 times larger buffer should be allocated to one line. // But because for each pixel we need 2 reads, the buffer should be doubled again. // The useful bytes are packed in the same buffer after reading is finished. // This is a lot of wasted memory, but it runs with DMA, which is a huge benefit! #define PIXEL_BUFFER_LENGTH (2*PIXELS_PER_LINE+1) uint8_t pixBuf[2][PIXEL_BUFFER_LENGTH]; //----------------------------------------------------------------------------- void TIMER_Setup(void) { gpio_set_mode(GPIOA, 1, GPIO_INPUT_FLOATING); // Slave mode: Reset mode (see RM0008, chap. 15.3.14, page 394) // ------------------------ // The counter and its prescaler can be reinitialized in response to an event on a trigger input. // Moreover, if the URS bit from the TIMx_CR1 register is low, an update event UEV is generated. // Then all the preloaded registers (TIMx_ARR, TIMx_CCRx) are updated. // // In the following example, the upcounter is cleared in response to a rising edge on TI2 input: // • Configure the channel 2 to detect rising edges on TI2. // - Configure the input filter duration (in this example, we don’t need any filter, so we keep IC1F=0000). // - The capture prescaler is not used for triggering, so you don’t need to configure it. // - The CC2S bits select the input capture source only, CC2S = 01 in the TIMx_CCMR1 register. // - Write CC2P=0 in TIMx_CCER register to validate the polarity (and detect rising edges only). // • Configure the timer in reset mode by writing SMS=100 in TIMx_SMCR register. // - Select TI2 as the input source by writing TS=101 in TIMx_SMCR register. // • Start the counter by writing CEN=1 in the TIMx_CR1 register. // // The counter starts counting on the internal clock, then behaves normally until TI2 rising edge. // When TI2 rises, the counter is cleared and restarts from 0. // In the meantime, the trigger flag is set (TIF bit in the TIMx_SR register) and an interrupt request, // or a DMA request can be sent if enabled (depending on the TIE and TDE bits in TIMx_DIER register). // // This event will trigger the DMA to save the content of GPIOB.IDR[1] to memory. timer_pause(TIMER2); // stop timer timer_init(TIMER2); // turn timer RCC on // configure PA2 = timer 2 channel 2 == input TI2 #define TIMER_RELOAD_VALUE 2 // must be adapted according to the results // as this mode is not supported by the core lib, we have to set up the registers manually. //(TIMER2->regs).gen->CR1 = TIMER_CR1_CEN; (TIMER2->regs).gen->CR2 = 0; (TIMER2->regs).gen->SMCR = (TIMER_SMCR_TS_TI2FP2 | TIMER_SMCR_SMS_RESET);//TIMER_SMCR_SMS_TRIGGER); (TIMER2->regs).gen->DIER = (TIMER_DIER_UDE); // enable DMA request on TIM2 update (TIMER2->regs).gen->SR = 0; (TIMER2->regs).gen->EGR = 0; (TIMER2->regs).gen->CCMR1 = TIMER_CCMR1_CC2S_INPUT_TI2; // IC2F='0000', IC2PSC='0', CC2S='01' (TIMER2->regs).gen->CCMR2 = 0; (TIMER2->regs).gen->CCER = (TIMER_CCER_CC2P); // inverse polarity, active low (TIMER2->regs).gen->CNT = 0;//TIMER_RELOAD_VALUE; // set it only in down-counting more (TIMER2->regs).gen->PSC = 0; (TIMER2->regs).gen->ARR = 0;//TIMER_RELOAD_VALUE; (TIMER2->regs).gen->CCR1 = 0; (TIMER2->regs).gen->CCR2 = 0; (TIMER2->regs).gen->CCR3 = 0; (TIMER2->regs).gen->CCR4 = 0; (TIMER2->regs).gen->DCR = 0; // don't need DMA for timer (TIMER2->regs).gen->DMAR = 0; // don't forget to set the DMA trigger source to TIM2-UP //timer_resume(TIMER2); // start timer } //----------------------------------------------------------------------------- void DMA_Setup(void) { dma_init(DMA1); uint32_t pmem = ((uint32_t)(&(GPIOB->regs->IDR)) + 1); // use GPIOB high byte as source dma_setup_transfer(DMA1, DMA_CH2, (uint8_t *)pmem, DMA_SIZE_8BITS, (uint8_t *)&pixBuf, DMA_SIZE_8BITS, (DMA_MINC_MODE));//| DMA_CIRC_MODE)); dma_set_priority(DMA1, DMA_CH2, DMA_PRIORITY_VERY_HIGH); //dma_set_num_transfers(DMA1, DMA_CH2, 2*PIXELS_PER_LINE); // 2 readings for each pixel //dma_enable(DMA1, DMA_CH2); } void setup() { //while(!Serial); delay(1000); pinMode(SD_CS,OUTPUT); digitalWrite(SD_CS,HIGH); // initialise the LCD tft.begin(); // use standard SPI port if (!sd.begin(SD_CS, SD_SCK_MHZ(50))) { sd.initErrorHalt(); } bufIndex = 0; tft.setRotation(1); // rotate 90° for landscape tft.setAddrWindow(0, 0, screen_h, screen_w); tft.fillScreen(ILI9341_BLUE); tft.setTextSize(2); tft.print("\n\nScreen size: "); tft.print(screen_w); tft.write('x'); tft.print(screen_h); tft.println("\n\nSetting up the camera..."); Serial.print("Setting up the camera..."); // initialise the camera if ( !camera.init() ) { tft.fillScreen(ILI9341_RED); tft.print("\n Camera init failure!"); Serial.println("failed!"); blink(0); } else { // tft.print("done."); Serial.println("done.\n"); } initTimerAndDMA(); } //----------------------------------------------------------------------------- void initTimerAndDMA() { tft.setRotation(1); // rotate 90° for landscape tft.setAddrWindow(0, 0, screen_w, screen_h); camera.waitForVsync(); camera.waitForVsyncEnd(); camera.waitForVsync(); camera.waitForVsyncEnd(); // enable the timer and corresponding DMA request DMA_Setup(); TIMER_Setup(); SPI.setDataSize(DATA_SIZE_8BIT); // set to 8 bit mode } void blink(uint8_t br) { pinMode(LED_PIN, OUTPUT); while(1) { digitalWrite(LED_PIN, LOW); delay(125); digitalWrite(LED_PIN, HIGH); delay(125); if (br) break; } } uint32_t loop_counter, line_counter; //----------------------------------------------------------------------------- void LCD2SD() { const int w = 320; const int h = 240; SdFile file; #define NUM_LINES_BUFFERED 12 uint8_t lineBufSD[w*3*NUM_LINES_BUFFERED]; unsigned char bmpFileHeader[14] = {'B', 'M', 0, 0, 0, 0, 0, 0, 0, 0, 54, 0, 0, 0 }; unsigned char bmpInfoHeader[40] = {40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 24, 0 }; unsigned long m; char name[] = "LCD_00.bmp"; // if name exists, create new filename for (int i = 0; i < 100; i++) { name[4] = i / 10 + '0'; name[5] = i % 10 + '0'; if (file.open(name, O_CREAT | O_EXCL | O_WRITE)) { break; } } // create image data int filesize = 54 + 4 * w * h; // w is image width, h is image height bmpFileHeader[ 2] = (unsigned char)(filesize ); bmpFileHeader[ 3] = (unsigned char)(filesize >> 8); bmpFileHeader[ 4] = (unsigned char)(filesize >> 16); bmpFileHeader[ 5] = (unsigned char)(filesize >> 24); bmpInfoHeader[ 4] = (unsigned char)( w ); bmpInfoHeader[ 5] = (unsigned char)( w >> 8); bmpInfoHeader[ 6] = (unsigned char)( w >> 16); bmpInfoHeader[ 7] = (unsigned char)( w >> 24); bmpInfoHeader[ 8] = (unsigned char)( h ); bmpInfoHeader[ 9] = (unsigned char)( h >> 8); bmpInfoHeader[10] = (unsigned char)( h >> 16); bmpInfoHeader[11] = (unsigned char)( h >> 24); file.write(bmpFileHeader, sizeof(bmpFileHeader)); // write file header file.write(bmpInfoHeader, sizeof(bmpInfoHeader)); // " info header m=millis(); uint8_t t; int lineOffset; for (int y = 0 ; y < h ; y++) { lineOffset = y%NUM_LINES_BUFFERED *3 * w; tft.readPixels24(0,(h-1)-y,320,(h-1)-y, lineBufSD + lineOffset); if ((y+1)%NUM_LINES_BUFFERED==0) { // swap colour channels from RGB to BGR for (int x = 0; x < w * 3 * NUM_LINES_BUFFERED; x+=3) { t=lineBufSD[x+2]; lineBufSD[x+2]=lineBufSD[x]; lineBufSD[x]=t; } file.write(lineBufSD, 3 * w * NUM_LINES_BUFFERED); } } Serial.print("Saved in ");Serial.print(millis()-m);Serial.println(" mS "); file.close(); } int totalFrames=0; void loop() { uint8_t * ptr = (uint8_t*)&pixBuf; // start of frame camera.waitForVsync(); digitalWrite(LED_PIN, !digitalRead(LED_PIN)); camera.waitForVsyncEnd(); if ( (loop_counter&(BIT2-1))==0 ) { if ( (loop_counter&(BIT7-1))==0 ) { Serial.write('\n'); } Serial.write('.'); } loop_counter ++; line_counter = screen_h; //noInterrupts(); // receive lines while ( (line_counter--) ) { // activate here the DMA and the timer dma_set_num_transfers(DMA1, DMA_CH2, 2*PIXELS_PER_LINE+1); // 2 readings for each pixel dma_clear_isr_bits(DMA1, DMA_CH2); dma_enable(DMA1, DMA_CH2); timer_resume(TIMER2); // start timer // one byte will be read instantly - TODO: find out why ? camera.waitForHref(); // wait for line start uint32_t t0 = millis(); // monitor the DMA channel transfer end, just loop waiting for the flag to be set. while ( !(dma_get_isr_bits(DMA1, DMA_CH2) & DMA_ISR_TCIF) ) { //Serial.print("DMA status: "); Serial.println(status, HEX); if ((millis() - t0) > 1000) { Serial.println("DMA timeout!"); blink(0); } if ( dma_get_isr_bits(DMA1, DMA_CH2) & DMA_ISR_TEIF ) { Serial.println("DMA error!"); blink(0); // error } if ( !camera.isHrefOn() ) break; // stop if over end of line } timer_pause(TIMER2); // stop timer dma_disable(DMA1, DMA_CH2); dma_clear_isr_bits(DMA1, DMA_CH2); if ( dma_get_isr_bits(DMA1, DMA_CH2) & DMA_ISR_TCIF ) { // Serial<< "2. DMA ISR: " << _HEX(DMA1->regs->ISR) << ", CNT: " << (DMA1CH2_BASE->CNDTR) << endl; Serial.println("DMA ISR bits reset error!"); blink(0); } // send pixel data to LCD //SPI.setDataSize(DATA_SIZE_8BIT); // set to 8 bit mode tft.pushColors((uint16_t*)ptr, 2*PIXELS_PER_LINE, 0); // 3rd parameter: send async //SPI.setDataSize(DATA_SIZE_16BIT); // set back to 16 bit mode if ( dma_get_isr_bits(DMA1, DMA_CH2) & DMA_ISR_TCIF ) { // Serial<< "3. DMA ISR: " << _HEX(DMA1->regs->ISR) << ", CNT: " << (DMA1CH2_BASE->CNDTR) << endl; Serial.println("DMA ISR bits reset error!"); blink(0); } } #define SAVE_EVERY_X_FRAMES 50 if ((totalFrames++)%SAVE_EVERY_X_FRAMES == (SAVE_EVERY_X_FRAMES-1)) { // timer_pause(TIMER2); (TIMER2->regs).gen->DIER = (0); // disable DMA request on TIM2 update LCD2SD(); initTimerAndDMA(); } //interrupts(); } unsigned long testText() { SPI.setDataSize(DATA_SIZE_16BIT); tft.fillScreen(ILI9341_BLACK); tft.setCursor(0, 0); tft.setTextColor(ILI9341_RED); tft.setTextSize(3); tft.println("LCD Screen reader\n"); tft.setTextColor(ILI9341_GREEN); tft.setTextSize(3); tft.println("rogerclark.net\n"); tft.setTextColor(ILI9341_BLUE); tft.setTextSize(3); tft.println(__TIME__); tft.println(random(100000)); return 0; }

Rogerclark
Пн 25 сентября 2017 г. 8:09
У меня была ошибка в коде, которую я опубликовал
// // Created by indrek on 4.12.2016. // // Adapted for ILI9341 by stevestrong on 29.07.2017 // #include #include #include const uint8_t SD_CS = PC15; SdFat sd; // TFT connection: // PB1 - TFT reset // PA2 - TFT D/C (data/command) // PB0 - TFT chip select // PA5 - TFT SPI CLK // PA6 - TFT SPI MISO // PA7 - TFT SPI MOSI // Camera connection: // PA8 - camera clock // PB3 - HREF // PA1 - pixel clock PCLK // PB5 - VSYNC // PB6 - I2C Clock // PB7 - I2C data // PB8..PB15 - pixel data // CPU@72MHZ -> 11fps, CPU@80MHZ-> 12.5fps BufferedCameraOV7670_QVGA camera(CameraOV7670::PIXEL_RGB565, BufferedCameraOV7670_QVGA::FPS_11p_Hz); #define LED_PIN PC13 #define TFT_CS PB0 #define TFT_DC PA2 #define TFT_RST PB1 Adafruit_ILI9341_STM tft = Adafruit_ILI9341_STM(TFT_CS, TFT_DC, TFT_RST); // Use hardware SPI #define SD_CS PC15 // Normally it is a portrait screen. Use it as landscape uint16_t screen_w = ILI9341_TFTHEIGHT; uint16_t screen_h = ILI9341_TFTWIDTH; uint16_t screenLineIndex; uint8_t bufIndex; #define PIXELS_PER_LINE ILI9341_TFTHEIGHT // The GPIO.IDR register can be only accessed in word (32 bit) mode. // Therefore a 4 times larger buffer should be allocated to one line. // But because for each pixel we need 2 reads, the buffer should be doubled again. // The useful bytes are packed in the same buffer after reading is finished. // This is a lot of wasted memory, but it runs with DMA, which is a huge benefit! #define PIXEL_BUFFER_LENGTH (2*PIXELS_PER_LINE+1) uint8_t pixBuf[2][PIXEL_BUFFER_LENGTH]; //----------------------------------------------------------------------------- void TIMER_Setup(void) { gpio_set_mode(GPIOA, 1, GPIO_INPUT_FLOATING); // Slave mode: Reset mode (see RM0008, chap. 15.3.14, page 394) // ------------------------ // The counter and its prescaler can be reinitialized in response to an event on a trigger input. // Moreover, if the URS bit from the TIMx_CR1 register is low, an update event UEV is generated. // Then all the preloaded registers (TIMx_ARR, TIMx_CCRx) are updated. // // In the following example, the upcounter is cleared in response to a rising edge on TI2 input: // • Configure the channel 2 to detect rising edges on TI2. // - Configure the input filter duration (in this example, we don’t need any filter, so we keep IC1F=0000). // - The capture prescaler is not used for triggering, so you don’t need to configure it. // - The CC2S bits select the input capture source only, CC2S = 01 in the TIMx_CCMR1 register. // - Write CC2P=0 in TIMx_CCER register to validate the polarity (and detect rising edges only). // • Configure the timer in reset mode by writing SMS=100 in TIMx_SMCR register. // - Select TI2 as the input source by writing TS=101 in TIMx_SMCR register. // • Start the counter by writing CEN=1 in the TIMx_CR1 register. // // The counter starts counting on the internal clock, then behaves normally until TI2 rising edge. // When TI2 rises, the counter is cleared and restarts from 0. // In the meantime, the trigger flag is set (TIF bit in the TIMx_SR register) and an interrupt request, // or a DMA request can be sent if enabled (depending on the TIE and TDE bits in TIMx_DIER register). // // This event will trigger the DMA to save the content of GPIOB.IDR[1] to memory. timer_pause(TIMER2); // stop timer timer_init(TIMER2); // turn timer RCC on // configure PA2 = timer 2 channel 2 == input TI2 #define TIMER_RELOAD_VALUE 2 // must be adapted according to the results // as this mode is not supported by the core lib, we have to set up the registers manually. //(TIMER2->regs).gen->CR1 = TIMER_CR1_CEN; (TIMER2->regs).gen->CR2 = 0; (TIMER2->regs).gen->SMCR = (TIMER_SMCR_TS_TI2FP2 | TIMER_SMCR_SMS_RESET);//TIMER_SMCR_SMS_TRIGGER); (TIMER2->regs).gen->DIER = (TIMER_DIER_UDE); // enable DMA request on TIM2 update (TIMER2->regs).gen->SR = 0; (TIMER2->regs).gen->EGR = 0; (TIMER2->regs).gen->CCMR1 = TIMER_CCMR1_CC2S_INPUT_TI2; // IC2F='0000', IC2PSC='0', CC2S='01' (TIMER2->regs).gen->CCMR2 = 0; (TIMER2->regs).gen->CCER = (TIMER_CCER_CC2P); // inverse polarity, active low (TIMER2->regs).gen->CNT = 0;//TIMER_RELOAD_VALUE; // set it only in down-counting more (TIMER2->regs).gen->PSC = 0; (TIMER2->regs).gen->ARR = 0;//TIMER_RELOAD_VALUE; (TIMER2->regs).gen->CCR1 = 0; (TIMER2->regs).gen->CCR2 = 0; (TIMER2->regs).gen->CCR3 = 0; (TIMER2->regs).gen->CCR4 = 0; (TIMER2->regs).gen->DCR = 0; // don't need DMA for timer (TIMER2->regs).gen->DMAR = 0; // don't forget to set the DMA trigger source to TIM2-UP //timer_resume(TIMER2); // start timer } //----------------------------------------------------------------------------- void DMA_Setup(void) { dma_init(DMA1); uint32_t pmem = ((uint32_t)(&(GPIOB->regs->IDR)) + 1); // use GPIOB high byte as source dma_setup_transfer(DMA1, DMA_CH2, (uint8_t *)pmem, DMA_SIZE_8BITS, (uint8_t *)&pixBuf, DMA_SIZE_8BITS, (DMA_MINC_MODE));//| DMA_CIRC_MODE)); dma_set_priority(DMA1, DMA_CH2, DMA_PRIORITY_VERY_HIGH); //dma_set_num_transfers(DMA1, DMA_CH2, 2*PIXELS_PER_LINE); // 2 readings for each pixel //dma_enable(DMA1, DMA_CH2); } boolean hasSD = true; void setup() { //while(!Serial); delay(1000); pinMode(SD_CS,OUTPUT); digitalWrite(SD_CS,HIGH); if (!sd.begin(SD_CS, SD_SCK_MHZ(50))) { hasSD=false; // sd.initErrorHalt(); } // initialise the LCD tft.begin(); // use standard SPI port bufIndex = 0; tft.setRotation(1); // rotate 90° for landscape tft.setAddrWindow(0, 0, screen_h, screen_w); tft.fillScreen(ILI9341_BLUE); tft.setTextSize(2); tft.print("\n\nScreen size: "); tft.print(screen_w); tft.write('x'); tft.print(screen_h); tft.println("\n\nSetting up the camera..."); Serial.print("Setting up the camera..."); // initialise the camera if ( !camera.init() ) { tft.fillScreen(ILI9341_RED); tft.print("\n Camera init failure!"); Serial.println("failed!"); blink(0); } else { // tft.print("done."); Serial.println("done.\n"); } initTimerAndDMA(); } //----------------------------------------------------------------------------- void initTimerAndDMA() { tft.setRotation(1); // rotate 90° for landscape tft.setAddrWindow(0, 0, screen_w, screen_h); camera.waitForVsync(); camera.waitForVsyncEnd(); camera.waitForVsync(); camera.waitForVsyncEnd(); // enable the timer and corresponding DMA request DMA_Setup(); TIMER_Setup(); SPI.setDataSize(DATA_SIZE_8BIT); // set to 8 bit mode } void blink(uint8_t br) { pinMode(LED_PIN, OUTPUT); while(1) { digitalWrite(LED_PIN, LOW); delay(125); digitalWrite(LED_PIN, HIGH); delay(125); if (br) break; } } uint32_t loop_counter, line_counter; //----------------------------------------------------------------------------- void LCD2SD() { unsigned char bmpFileHeader[14] ;//= {'B', 'M', 0, 0, 0, 0, 0, 0, 0, 0, 54, 0, 0, 0 }; unsigned char bmpInfoHeader[40] ;//= {40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 24, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }; static int lastSavedFileNumber = -1; char name[12];// = "LCD_0000.bmp"; const int w = 320; const int h = 240; SdFile file; #define NUM_LINES_BUFFERED 12 // WARNING NUM_LINES_BUFFERED MUST BE A FACTOR OF 240 uint8_t lineBufSD[w*3*NUM_LINES_BUFFERED]; unsigned long m; // if name exists, create new filename if ((lastSavedFileNumber+1)>511) { return; } for (int i = (lastSavedFileNumber+1); i < 512; i++) { sprintf(name,"LCD_%04d.bmp",i); Serial.print("\nTrying name ");Serial.println(name); if (file.open(name, O_CREAT | O_EXCL | O_WRITE)) { lastSavedFileNumber=i; break; } } // create image data int filesize = 54 + 4 * w * h; // w is image width, h is image height memset(bmpFileHeader,0,sizeof(bmpFileHeader)); memset(bmpInfoHeader,0,sizeof(bmpInfoHeader)); bmpFileHeader[0]='B'; bmpFileHeader[1]='M'; bmpFileHeader[ 2] = (unsigned char)(filesize ); bmpFileHeader[ 3] = (unsigned char)(filesize >> 8); bmpFileHeader[ 4] = (unsigned char)(filesize >> 16); bmpFileHeader[ 5] = (unsigned char)(filesize >> 24); bmpFileHeader[10]=54; bmpInfoHeader[0]=40; bmpInfoHeader[ 4] = (unsigned char)( w ); bmpInfoHeader[ 5] = (unsigned char)( w >> 8); bmpInfoHeader[ 6] = (unsigned char)( w >> 16); bmpInfoHeader[ 7] = (unsigned char)( w >> 24); bmpInfoHeader[ 8] = (unsigned char)( h ); bmpInfoHeader[ 9] = (unsigned char)( h >> 8); bmpInfoHeader[10] = (unsigned char)( h >> 16); bmpInfoHeader[11] = (unsigned char)( h >> 24); bmpInfoHeader[12]=1; bmpInfoHeader[14]=24; file.write(bmpFileHeader, sizeof(bmpFileHeader)); // write file header file.write(bmpInfoHeader, sizeof(bmpInfoHeader)); // " info header m=millis(); uint8_t t; int lineOffset; for (int y = 0 ; y < h ; y++) { lineOffset = y%NUM_LINES_BUFFERED *3 * w; tft.readPixels24(0,(h-1)-y,320,(h-1)-y, lineBufSD + lineOffset); if ((y+1)%NUM_LINES_BUFFERED==0) { // swap colour channels from RGB to BGR for (int x = 0; x < w * 3 * NUM_LINES_BUFFERED; x+=3) { t=lineBufSD[x+2]; lineBufSD[x+2]=lineBufSD[x]; lineBufSD[x]=t; } file.write(lineBufSD, 3 * w * NUM_LINES_BUFFERED); } } Serial.print("Saved in ");Serial.print(millis()-m);Serial.println(" mS "); file.close(); } int totalFrames=0; void loop() { uint8_t * ptr = (uint8_t*)&pixBuf; // start of frame camera.waitForVsync(); digitalWrite(LED_PIN, !digitalRead(LED_PIN)); camera.waitForVsyncEnd(); if ( (loop_counter&(BIT2-1))==0 ) { if ( (loop_counter&(BIT7-1))==0 ) { Serial.write('\n'); } Serial.write('.'); } loop_counter ++; line_counter = screen_h; //noInterrupts(); // receive lines while ( (line_counter--) ) { // activate here the DMA and the timer dma_set_num_transfers(DMA1, DMA_CH2, 2*PIXELS_PER_LINE+1); // 2 readings for each pixel dma_clear_isr_bits(DMA1, DMA_CH2); dma_enable(DMA1, DMA_CH2); timer_resume(TIMER2); // start timer // one byte will be read instantly - TODO: find out why ? camera.waitForHref(); // wait for line start uint32_t t0 = millis(); // monitor the DMA channel transfer end, just loop waiting for the flag to be set. while ( !(dma_get_isr_bits(DMA1, DMA_CH2) & DMA_ISR_TCIF) ) { //Serial.print("DMA status: "); Serial.println(status, HEX); if ((millis() - t0) > 1000) { Serial.println("DMA timeout!"); blink(0); } if ( dma_get_isr_bits(DMA1, DMA_CH2) & DMA_ISR_TEIF ) { Serial.println("DMA error!"); blink(0); // error } if ( !camera.isHrefOn() ) break; // stop if over end of line } timer_pause(TIMER2); // stop timer dma_disable(DMA1, DMA_CH2); dma_clear_isr_bits(DMA1, DMA_CH2); if ( dma_get_isr_bits(DMA1, DMA_CH2) & DMA_ISR_TCIF ) { // Serial<< "2. DMA ISR: " << _HEX(DMA1->regs->ISR) << ", CNT: " << (DMA1CH2_BASE->CNDTR) << endl; Serial.println("DMA ISR bits reset error!"); blink(0); } // send pixel data to LCD //SPI.setDataSize(DATA_SIZE_8BIT); // set to 8 bit mode tft.pushColors((uint16_t*)ptr, 2*PIXELS_PER_LINE, 0); // 3rd parameter: send async //SPI.setDataSize(DATA_SIZE_16BIT); // set back to 16 bit mode if ( dma_get_isr_bits(DMA1, DMA_CH2) & DMA_ISR_TCIF ) { // Serial<< "3. DMA ISR: " << _HEX(DMA1->regs->ISR) << ", CNT: " << (DMA1CH2_BASE->CNDTR) << endl; Serial.println("DMA ISR bits reset error!"); blink(0); } } #define SAVE_EVERY_X_FRAMES 11 if (hasSD && (totalFrames++)%SAVE_EVERY_X_FRAMES == (SAVE_EVERY_X_FRAMES-1)) { // timer_pause(TIMER2); (TIMER2->regs).gen->DIER = (0); // disable DMA request on TIM2 update LCD2SD(); initTimerAndDMA(); } //interrupts(); }

Rogerclark
Пн 25 сентября 2017 г. 10:20 утра
Просто на небольшое удовольствие, я оставил камеру, работающую, укажите из окна, потребовалось 512 изображений, которые я использовал ffmpeg, чтобы преобразовать в короткое видео

https: // drive.Google.com/open?ID = 0B4ADV ... Fboczh5meu

КСТАТИ.

Цвета выглядят странно, но солнце садилось за камеру, поэтому цвет был более точным, чем выглядит.

Zoomx
Пн 25 сентября 2017 г. 14:10
К сожалению, мой модуль OV7670 кажется где -то потерянным :(

Rogerclark
Вторник 26 сентября 2017 г. 10:44
Мне было интересно, были ли какие -нибудь лучшие наборы данных регистрации камеры, поэтому я попробовал набор из Arducam

https: // github.com/arducam/arduino/tree/master/arducam

Для OV7670.

Коррекция цвета была такой же, как и в коде Индрека, однако изображение, по -видимому, инвертировано / вращается.

Мне пришлось повернуть дисплей на 180 градусов, чтобы получить ту же картинку.

К сожалению, его нелегко сравнить настройки регистра, потому что код S Indrek использует много определений, но версия Arducam - это просто необработанные номера.

Я интенсивно думал, что, возможно, я мог бы изменить параметры, чтобы мне не нужно было читать из LCD -линии по линии, чтобы вертикально зеркало, но мне удалось найти настройку, которая сделает это, изображение на ЖК -дисплее будет выглядеть странно

Стивестронг
Вторник 26 сентября 2017 г. 11:31
Лучшие настройки регистра для OV7670? Это своего рода наука о вуду...
Это то, что я нашел здесь: when x"06" => sreg <= x"8C00"; -- RGB444 Set RGB format when x"07" => sreg <= x"0400"; -- COM1 no CCIR601 when x"08" => sreg <= x"4010"; -- COM15 Full 0-255 output, RGB 565 when x"09" => sreg <= x"3a04"; -- TSLB Set UV ordering, do not auto-reset window when x"0A" => sreg <= x"1438"; -- COM9 - AGC Celling when x"0B" => sreg <= x"4fb3"; -- MTX1 - colour conversion matrix when x"0C" => sreg <= x"50b3"; -- MTX2 - colour conversion matrix when x"0D" => sreg <= x"5100"; -- MTX3 - colour conversion matrix when x"0E" => sreg <= x"523d"; -- MTX4 - colour conversion matrix when x"0F" => sreg <= x"53a7"; -- MTX5 - colour conversion matrix when x"10" => sreg <= x"54e4"; -- MTX6 - colour conversion matrix when x"11" => sreg <= x"589e"; -- MTXS - Matrix sign and auto contrast when x"12" => sreg <= x"3dc0"; -- COM13 - Turn on GAMMA and UV Auto adjust when x"13" => sreg <= x"1100"; -- CLKRC Prescaler - Fin/(1+1)

Rogerclark
Вторник 26 сентября 2017 г. 9:25 вечера
Спасибо, Стив

Я думал, что, возможно, настройки Arducam могут быть лучше, так как они работали над этими камерами в течение нескольких лет, но я заменил настройки по умолчанию, на Arducam, и, насколько я мог сказать, цвет выглядел одинаково.

То, как код регистров разделен на настройки по умолчанию и настройки для каждого разрешения, хорошо, так как я мог бы просто заменить по умолчанию, и камера все еще работала, даже если я уверен, что Arducam использует разрешение 640x480.

Я думаю, что у Arducam есть какая -то программа GUI PC, которая позволяет изменять настройки Color (регистр) на Fly и для просмотра результирующего изображения на ПК, но их оборудование представляет собой FPGA и использует устройство USB с захватом изображения. и, возможно, также управляющее устройство. (Или, возможно, управление проходит через прикрепленное устройство AVR Arduino)

Я думаю, что можно было бы сделать примерно одно и то же, за исключением случаев отправить изображение через сериал, так что это было бы только для захвата изображения

Я думаю, я мог бы реализовать упрощенный контроль через серийный, e.G Отправить регистр, значение и получить код, чтобы написать его в камеру в конце кадра (хотя я не знаю, будет ли время сделать это без прерывания потока данных из камеры

Rogerclark
Ср 27 сентября 2017 г. 6:44
Я написал немного кода Python, чтобы прочитать изображение через сериал
OV7670_TO_PC.JPG
OV7670_TO_PC.JPG (17.21 киб) просмотрено 903 раз

Rogerclark
Солнце 8 октября 2017 г. 3:40
Ребята

Я совершил изменения, которые у меня были локально, что позволяет чтению LCD с помощью кода Стива плюс еще одна функция для чтения RGB24 -бита (на основе кода Стива)

Я думаю, что, возможно, я должен добавить LIB Стива OV7670, который работает для меня, в библиотеки F1 ??

Концзакп
Ср 11 октября 2017 г. 9:59
Да, пожалуйста, сделайте это .... Я все еще жду своего аппаратного обеспечения, но я тоже не могу дождаться, чтобы проверить его ....

Rogerclark
Ср 11 октября 2017 г. 10:33
ХОРОШО

Я прибегаю код и опубликую его на выходных

PS также изготовление печатной платы для синей таблетки + OV767 + LCD

Но я продолжаю передать свое мнение о том, нужно ли он также подключиться к булавкам SD или контактным выводам на ЖК -плате

Я думаю, что мне придется удалить часть платы, которая подключается к булавкам SD, потому что это делает доску слишком большой и дорогостоящей.

Так что мне нужно сделать немного редизайн.

Концзакп
Ср. 01 ноября 2017 г. 15:58
Я наконец получил все аппаратное обеспечение. Роджер, вы опубликовали все изменения с OV7670 LIB на GitHub? Я хотел начать с самого начала.

Rogerclark
Ср. 01 ноября 2017 г. 20:00
Я дважды проверю свой код и что на GitHub

Концзакп
Сб, 04 ноября 2017 г. 15:52
Пожалуйста, также добавьте OV7670 LIB в библиотеки STM32F1, чтобы получить полный комплект

Концзакп
Пн 13 ноября 2017 г. 9:24 утра
Бьюсь об заклад, ты забыл обо мне? Или, может быть, вы опубликовали это где -нибудь еще здесь https: // github.com/rogerclarkmelbourne/ ... /библиотеки ?

Zoomx
Пн 13 ноября 2017 г. 10:34
Тем временем вы можете проверить этот двоичный
http: // stm32duino.com/viewtopic.PHP?f = 1 ... 260#P33895
Использование соединений, описанных в последовательном посте, если у вас есть тот же дисплей.

Rogerclark
Чт 16 ноября 2017 г., 22:29
[Концзакп - Пн, 13 ноября 2017 г. 9:24 утра] - Бьюсь об заклад, ты забыл обо мне? Или, может быть, вы опубликовали это где -нибудь еще здесь https: // github.com/rogerclarkmelbourne/ ... /библиотеки ?
Разве вы не можете просто добавить библиотеку Стива в свою папку библиотеки Arduino ?

Концзакп
Пт 17 ноября 2017 г. 10:59
Конечно, я могу, но я думал, что вы внесли некоторые изменения в Lib Стива, и ранее вы упомянули, что добавите эту либера. Но если нет, то все в порядке, я получу это от GitHub Стива :)

Rogerclark
Сб 18 ноября 2017 г. 11:10
К вашему сведению.

Я попытался взять свою камеру и дисплей сегодня, но обнаружил, что множество проводов разорвалась после того, как я взял ее в клуб Arduino, чтобы показать им некоторые вещи, которые вы можете сделать с STM32.

Поэтому мне потребовалось некоторое время, чтобы разобраться, куда пошли все провода, и снова продал их все (около 6 проводов разбили дисплей)

Это код, который я использую.
live_ov7670.молния
(23.94 киб) скачано 97 раз

Гунгсукма
Вт 26 декабря 2017 г. 10:21
Я попробовал Stevestrong's STM32_OV7670.7Z со страницы 1
Но это не работает с моей синей таблеткой (STM32F103C8T6) и OV7670 не FIFO.

Я могу загрузить эскиз и запустить его, но последовательный монитор всегда останавливается на «Настройке камеры..."
Это на cam_init () на pid = rdreg (reg_pid);

Вот соединения булавки:
OV7670 STM32F103C8T6
1. VCC 3.3В
2. GND GND
3. SCL PB6
4. SDA PB7
5. VSYNC PB4 (IN)
6. Href PB5 (в)
7. PCLK PB3 (IN)
8. XCLK PB0 (OUT)
9. D7..D0 PA7..PA0 (в)
10. Сбросить не подключен
11. PWDN не подключен
Может быть, сброс и PWDN -контакты должны быть где -то подключены, или SCL и SDA нуждаются
или код истек (он с 2015 года), или мой модуль сломан.
Пожалуйста, помогите.

Стивестронг
Вт 26 декабря 2017 г. 10:45
SCL и SDA нуждаются в внешнем подтягивании.

ZMEMW16
Вт 26 декабря 2017 г. 11:57 утра
3K3 до 3.3В
4.7K/5.1K до 5 В
Ходят слухи, что 10 тысяч или ниже будет работать
SRP

Сеско
Вт 26 декабря 2017 г., 17:55
My Grabber работает с кодом Stevestrong от Page1, но только если я изменяю ввод часов Pixel от PB3 на PB8.
Мой чертежи PB3 сломлен или есть проблема с PB3 ?

ZMEMW16
Вт 26 декабря 2017 г., 19:33
Вы используются для отладки и / или программирования ST-Link
Итак, вам нужно добавить disableDebugPorts();

Сеско
Вт 26 декабря 2017 г., 20:00
Тай.

К сожалению, инвалид -баггпорт (); Заблокируется дальнейшая загрузка Stlink, если я каждый раз не сбросил чертежи.

ZMEMW16
Вторник 26 декабря 2017 г. 8:34 вечера
играл с Cubemx с 103C8
2 Провод, как говорит PA13/PA14
3 провода «Trace Async» добавляет PB3
4 Провод добавляет PA15 к выше
5 Провод добавляет PB4 к выше

Я не предполагаю, что вы включили Trace Async Mode, поскольку он Clobbers PB3 ?

Вы используете кабельный кабель 20WAY ST-Link, а не USB-палочка (SDCLK/SDIO/GND)

Может быть, стоит попробовать - если вы добавите захват кнопки «бросить» внутри функции петли и что -то похожее на if (buttonpress == true){ EnableDebugPorts(); while(1) {} }

Сеско
Ср 27 декабря 2017 г. 12:06
> следа асинхронности

Не знаю, что это такое. Да, я использую USB-плесень, 4 провода, включая питание.

Нажатие сброса при запуске загрузки STLINK работает с отключенным от Debugport.

Я просто оставил PixClock на PB8 вместо PB3. 2 строки изменения кода.
Тогда я наконец -то заставил загрузчик Maple Bootloader, и теперь я использую его вместо stlink.

Я также изменил код, чтобы он был блоком, ожидая pixclock или href. Немного медленнее, чем блокировка "в то время как", но безопаснее. while( VSYNC ); //wait for low line = 0; noInterrupts(); while (!VSYNC) // as long as high { if(HREF) { if (was_href_lo) { was_href_lo = false; // linesync pck = 0; line++; } if (PCLK) { if (was_pix_lo) { was_pix_lo = false; if ( pck&0x01 && line>1] = CAM_DATA; pck++; } } else was_pix_lo = true; } else was_href_lo = true; } interrupts(); Serial.println("> image acquisition done.");

ZMEMW16
Ср 27 декабря 2017 г. 14:01
Это варианты внутри элемента Sys/Debug, как показано в Cubemx.

Trace Async - я думаю, предоставляет некоторую информацию, позволяющую вам следить за потоком программы.
ISTR, что есть аппаратный мод для 10PIN USB -блоков, позволяющих использовать его.
Это также первый из вариантов использования PB3, который вас испортит.

Какая у вас настройка и т. Д ?

Просто для развлечения, не могли бы вы попробовать это предложение о выходе с помощью мощного вызова ?
SRP

Сеско
Ср 27 декабря 2017 г. 20:07
> Какая у вас настройка и т. Д ?

Изображение

> Выход с помощью мощного вызова

Отключение произведений. Включение не требуется, у меня нет кнопки, и я сохранил Stlink :)

ZMEMW16
Ср 27 декабря 2017 г. 11:50
Это было не совсем то, что я имел в виду, когда просил вашу настройку :ржу не могу:
Больше похоже на OS Win/Linux/Mac, версия Arduino, какая ядро ​​и больше аналогичного ILK :!:
SRP

Сеско
Чт 28 декабря 2017 г. 14:11
Ничего особенного, стандартный Bluepill $ 3, стандартный $ 3 OV7670, Windows7, No Display.

STM32F103 имеет 20 КБ SRAM, недостаточно для 160x120. Мне, возможно, придется использовать 80x64 или даже ниже, чтобы запустить компрессор JPEG на нем. Я еще не нашел компилируемый компрессор JPEG Arduino IDE. Идея состоит в том, чтобы иметь декомпрессора на ПК Win7 и отобразить там изображение.

У меня есть версия этого Arduino Uno с Serial Comm на ПК и программа «обработка» для отображения изображения BMP. AVR -код отличается, без внутреннего хранилища изображения из -за 2 КБ SRAM.

В будущем это должно мигрировать в ESP32 и отправить сжатые картинки в реальном времени в режиме вещания. Затем это может использоваться в качестве FPV -подачи в плоскости RC или квадроцикле RC. Видео от плоскости к пользователю, данные RC от пользователя до самолета, двунаправленная.

Они делают 10 км здесь с антенной Hi Gain Antenna. Камера - это jpeg, способный OV2640 (у меня нет):
https: // www.YouTube.com/watch?v = yclb2eitdye

Сеско
Пт 19 января 2018 г. 13:21
Я попытался взять раму, 80x160 пиксель и отправить его на ПК через сериал. Это 128000 бит, должно потребоваться 0.5 секунд при 250 кбо, но это требуется 20 секунд.

Это единственный байт "сериал.Напишите (байт) «медленно или что происходит?
Кто -нибудь тестировал камеру OV2640 с Build в компрессоре JPEG?

160x80 BW рама:
Изображение

РЕДАКТИРОВАТЬ:
Я попытался написать целую целую линию на сериал, и это гораздо быстрее. "Сериал.написать (linebuf, lineize); "

Стивестронг
Пт 19 января 2018 г. 13:30
В общем, Single Writes всегда медленнее, чем буферированные записи.
С использованием Serial.write(buffer, nr_bytes);

Сеско
Пт 19 января 2018 г. 14:26
Я беру картинку в баран, а затем отправляю его на USB. Резолюция отстой из -за 20 КБ ОЗУ, я использую 120x80 BW, 12800 байтов для кадровую буфер.
Я изменил, чтобы написать целую линию с одной записью, и сейчас гораздо быстрее.

Любая помощь с компрессором JPEG?

Dispcam - это программа дисплея, источник обработки. Использует 255 в качестве стартового кадра, 254 начала линии, 253 конец PIC. Значения пикселей усечены от 0 до 250. Вы должны нажать Dispcam, чтобы запустить захват кадра.
Примечание я изменил pclk_pin на PB8 вместо PB3

Rogerclark
Сб 20 января 2018 г., 4:09
@CESCO

Если у вас подключен дисплей .эн.g ili9341 Вы можете использовать его в качестве хранилища рамки, хотя и читая данные не так быстро

Рободжушен
SAT 28 апреля 2018 г. 10:01
Привет!
Я разработал проект Machinevision с OV7670 и Bluepill. Я успешно использовал оригинальную опросную версию Stevstrongs (спасибо!). Я решил попробовать DMA-версию для достижения более высокой кадров. Однако я изо всех сил пытаюсь понять, как DMA-чтение хранит пиксели и как получить к ним доступ. Я пытаюсь сохранить, например, 80x80 BlackScale Image (YUV) или цветное изображение в UINT8_T 2D-буфер. Я использую QQVGA и 7,5 Гц.

Может ли кто -нибудь помочь понять это? Я потратил много времени, пытаясь выяснить это сам, но это немного вне меня.

1. Почему данные сохраняются в массиве uint8_t pixBuf[2][PIXEL_BUFFER_LENGTH];

Стивестронг
SAT 28 апреля 2018 г. 10:21
Не могли бы вы опубликовать ссылку на подержанную версию?

Я предполагаю, что SW использует двойной брюк, поэтому массив двухмерный. В то время как DMA заполняет один буфер, другой можно обработать: зачитывайте, отправляется в ЖК -дисплей или сохранен.
Но имейте в виду, что обработка должна быть настолько быстрой, насколько это возможно, обработка одной кадры должна быть закончена, прежде чем другой хранится в буфере DMA.
Ваша процедура копирования выглядит как очень много времени, это может быть причиной, почему она висит.

Рободжушен
Сб 28 апреля 2018 г. 10:43
Это один из тестов, которые не висят. Но Singe Printed Pixel Do не изменился, даже если я покрываю объектив или укажу на это на свет. Все файлы из вашего репо. Как вы думаете, есть ли шанс прочитать пиксели в буфер между линиями?

Стивестронг
Сб 28 апреля 2018 г., 13:17
Я просмотрел код, кажется, что DMA будет хранить только одну строку за раз.
Следующая строка будет храниться после обработки пикселей.
Причина этого заключается в том, что DMA для хранения данных камеры не может быть нарушена с помощью другого процесса DMA.
Теперь ваш кусок кода находится внутри The Whice (line_counter--) Loop.
Это означает, что вы должны хранить только одну линию в BUF.
Попробуйте что -то вроде: for(uint8_t i = 0; i<80; i++) { buf[screen_h-line_counter-1][i]=*ptr++; }

Рободжушен
Солнце 29 апреля 2018 г., 19:54
Спасибо за совет! Я попробовал обоих путей, и мне пришлось положить
buf_ptr = &buf;

Рободжушен
Пт, 04 мая 2018 г., 18:49
Мне удалось получить OV7670+TFT, работая с эскизом, предоставленным Роджером в этой теме. Я должен был добавить инвалидбагпорт (). Это сработало с красивой кадром. Единственная проблема заключалась в том, что цвет менялся постоянно между нормальным и плохо перекованным в сторону красного. Авто-белый баланс работал странным образом. Может, может попробовать эти настройки: https: // hinksmallthings.WordPress.com/2 ... th-ov7670/

Тем не менее, я тоже не смог прочитать кадры для буфера с этим кодом. Я провел некоторое тестирование и получил несколько странных результатов. Программа замерзла, если я попытался скопировать какие-либо данные в другой буфер, даже если это не был PixBuf, используемый DMA-Funcitons. Такие же копии процедуры велись нормально в других частях программы. Я приложу один из моих тестовых кодов.

Я думаю, что проблема не время, потому что код не застрял, даже если я добавляю различные задержки в цикл, включающий изображение, он работает нормально с короткими задержками и просто замедляется с более длинными задержками.

Если я понял это правильно, акцидовать в таблицу данных, должно быть достаточно времени, чтобы копировать данные в буфер. Я, например, копирование 320 байтов заняло 86us. DataHeet говорит, что с QVGA FPS 15 (12 МГц PCLK) существует около 42,6US GAP между двумя линиями. (На самом деле таблица данных OV7725, потому что Datahate OV7670 показывает только время VGA, но кажется, что это то же самое), с более низким PCLK и QQVGA должно быть еще больше времени.

Я должен, возможно, покопаться в код Indreks и попытаться заставить его работать. Или просто постарайтесь быть довольны очень низкой кадрой. Хорошая сторона с низкой кадров - это то, что можно сделать некоторую обработку между линиями, плохая сторона заключается в том, что если старт следующий кадр пропущен из -за обработки, она займет много времени, чтобы ждать следующего.

Rogerclark
Пт, 04 мая 2018 г., 21:15
На данный момент мой проект OV7670 сломан, потому что провода от камеры до синей таблетки продолжают ломаться

Мне, вероятно, нужно приклеить синюю таблетку и камеру на доску и переписать, но есть много проводов, и я дону’Термо сделать это в данный момент.

Кстати.

Я начал создавать дизайн печатной платы для этого, но я так и не закончил это :-(

Козух
Вторник 14 августа 2018 11:26
Я стараюсь использовать код из этого репо для запуска на STM32F103C8T6:
https: // github.com/stevstrong/liveov7670_stm32

Однако он не будет компилироваться, и я получаю следующую ошибку:
https: // github.com/stevstrong/liveov7670_stm32/выпуски/1

Любая помощь оценена. Я использую неправильный код проекта? У GitHub, кажется, есть работа DMA, который мне интересует. Или 320x240@15fps возможна без DMA тоже?

Стивестронг
Ср 15 августа 2018 г., 5:15 утра
Этот проект использует DMA один раз для выборки данных из камеры в память, а второй для передачи отобранных данных из памяти в TFT по SPI. Это работает только с DMA. Тем не менее, я думаю, что оригинальный проект от Indreluuk не использует DMA.

Козух
Сб 18 августа 2018 11:02
@stevestrong

Я получил версию STM32F103, каким -то образом работала из вашего github Repo. Я использую Prescaler = 2 и, вероятно, обошел эти 14.6 кадров в секунду. Я получаю полосы радуги вверху и справа от дисплея (оба шириной около 20 пикселей), но в остальном изображение в порядке.

Интересно, для чего нужен следующий код в .INO -файл - Внешний цикл запускается каждый 4 -й кадр и внутренний каждые 128 -й кадр. Если я прокомментирую это, я получу совершенно черную картинку. Можете ли вы сказать, что этот код хорош для?
if ( (loop_counter&(BIT2-1))==0 ) { if ( (loop_counter&(BIT7-1))==0 ) { Serial.write('\n'); } Serial.write('.'); }

Стивестронг
Sun 19 августа 2018 г., 7:06 утра
@kozuch,
Я переместил ваш пост здесь, это место для обсуждения версии F1.

Кодовая часть, которую вы указали, является лишь живым тикером для USB -сериала, чтобы проверить, работает ли код или висел.
HM, мне, возможно, потребуется повторно проверить код, я эветально нашел лучший способ настроить таймер, чтобы вызвать DMA.

Козух
Sun 19 августа 2018 г. 8:46 утра
Похоже, функция Loop () очень чувствительна к времени кода даже вне. Я работаю по пробным и ошибкам и добавляю код за пределы, пока обычно ломает картинку.

Я прочитал в другой (F4) потоке, чтобы пропустить передачу DMA в кучу и напрямую написать с камеры в SPI - вы имеете в виду это улучшение? Сколько он может сделать вещи быстрее?

Стивестронг
Sun 19 августа 2018 г. 10:32 утра
Основная проблема заключается в том, что камера выглядит так, как иногда LISES LINES.
Например, он выводит строки 1..30, а затем больше нет данных до следующего VSYNC.
Вот почему прямая передача данных в SPI сложно, в этих случаях нужно повторно переосмыслить окно, где написать данные в TFT Buffer.

Но я имел в виду другую настройку таймера, которая может улучшить скорость триггера DMA. Теперь таймер настроен на режим сброса, но в последнее время я экспериментировал с внешним настройкой триггера, что может дать лучший результат.

Козух
Sun 19 августа 2018 г. 14:48
На этих 320x240@15 кадров в секунду эффект прокатного затвора кажется мне довольно серьезным (у меня есть движущаяся сцена). У датчика есть внутренний буфер линии или необходимо зачитывать линию до того, как будет выявлено следующее? Несмотря на то, что я вижу FIFO на функциональной блок -диаграмме в таблице данных, я боюсь, что не может быть много памяти. Затем поднятие PCLK может сделать считывание быстрее и помочь смягчить эффект затвора на прокат - это правильно?

Единственный предварительный прекалер, работающий для меня, - это 2 (изображение имеет только незначительные проблемы с 2 сторон). Другие прокалиры также должны работать? С Прескалером = 2 PCLK составляет 12 МГц - это правильно? (Xclk = 24 МГц)

Когда я установил Прескалер на 1, я получаю около 20% изображения несколько правильного (плохие цвета, но содержимое реально), а остальные - радужные полосы. Я предполагаю, что таймер PCLK (таймер2) продолжает в норме, но SPI для отображения перегружено. Я знаю, что скорость передачи SPI максимально выявлена ​​с помощью Prescaler = 2, так что этого следует ожидать.

Кстати, Timer2 действительно работает на полном 72 МГц? Внутренний светодиод мигает примерно в два раза быстрее, что указывает на то, что от камеры будет указано около 30 кадров в секунду.

Стивестронг
Sun 19 августа 2018 г. 15:27
При более высоком FPS, чем 15, SPI DMA перекрывается и нарушает процесс отбора проб камеры DMA. это цветные полосы в начале и в конце линий.
Я действительно должен попробовать прямой DMA от камеры до SPI, когда у меня есть время...

72 МГц делятся на 100 кода