STM32F4xx + DCMI + USB Custom (CDC + UVC)

от автора

Произошла в моей жизни такая необходимость как подключение камеры (точнее тепловизора) к конечному устройству по USB. Камера с интерфейсом DCMI и протоколом BT656. Собственно, поэтому была разработана (написана) программа. Постараюсь изложить некоторые особенности.

Ссылка на программу прикреплена в конце публикации.

Кадр

Кадр размещается во внешнюю SDRAM (Synchronous Dynamic Random Access Memory).

Инициализация и настройка таймингов памяти (…/User/Src/sdram.c)

void MX_FMC_Init(void) {   FMC_SDRAM_TimingTypeDef SdramTiming = {0};    /** Perform the SDRAM1 memory initialization sequence   */   hsdram1.Instance = FMC_SDRAM_DEVICE;   /* hsdram1.Init */   hsdram1.Init.SDBank = FMC_SDRAM_BANK1;   hsdram1.Init.ColumnBitsNumber = FMC_SDRAM_COLUMN_BITS_NUM_8;   hsdram1.Init.RowBitsNumber = FMC_SDRAM_ROW_BITS_NUM_12;   hsdram1.Init.MemoryDataWidth = FMC_SDRAM_MEM_BUS_WIDTH_16;   hsdram1.Init.InternalBankNumber = FMC_SDRAM_INTERN_BANKS_NUM_4;   hsdram1.Init.CASLatency = FMC_SDRAM_CAS_LATENCY_3;   hsdram1.Init.WriteProtection = FMC_SDRAM_WRITE_PROTECTION_DISABLE;   hsdram1.Init.SDClockPeriod = FMC_SDRAM_CLOCK_PERIOD_3;   hsdram1.Init.ReadBurst = FMC_SDRAM_RBURST_DISABLE;   hsdram1.Init.ReadPipeDelay = FMC_SDRAM_RPIPE_DELAY_1;   /* SdramTiming */   //This settings are taken from the memory manual   SdramTiming.LoadToActiveDelay = 2;   SdramTiming.ExitSelfRefreshDelay = 7;//11; 7   SdramTiming.SelfRefreshTime = 4;//7; 4   SdramTiming.RowCycleDelay = 6;//10; 6   SdramTiming.WriteRecoveryTime = 2;   SdramTiming.RPDelay = 2;   SdramTiming.RCDDelay = 2;    if (HAL_SDRAM_Init(&hsdram1, &SdramTiming) != HAL_OK)   {     Error_Handler( );   }  }

Настройки взяты из примеров (коих очень много, даже ссылку оставлять не буду) и даташита на микросхему (IS42S16800F-6tli).

Захват и размещение кадра в памяти (…/User/Src/camera.c):

uint8_t GrabCamFrame(void) { CameraTypeDef *ptr = &Camera; if(ptr->FlagFrameTrans)return 0;//this means the frame is sent via uvc. you can parse cmd. if(ptr->CmdFrameComplit == CAM_INIT) { HAL_DCMI_Start_DMA(&hdcmi,DCMI_MODE_CONTINUOUS,SDRAM_BANK_ADDR,FRAMESIZEWORDS); while(pcamera->FlagFrameComplit==0) {     ; } GPIOC->ODR |= (1<<5); ptr->FlagFrameTrans=1; pcamera->FlagFrameComplit=0; } return ptr->FlagFrameTrans; }

DCMI_MODE_CONTINUOUS – непрерывный режим работы.

SDRAM_BANK_ADDR – адрес во внешней памяти, куда записываются байты кадра 0xC0000000.

FRAMESIZEWORDS – размер кадра в 16-битном поле.

 GrabCamFrame() вызывается в основном потоке. После захвата кадра и размещения в памяти, устанавливается флаг FlagBusy, используется как признак передачи кадра по USB.
Использована блокирующая функция. Есть необходимость от нее избавиться.

void HAL_DCMI_LineEventCallback(DCMI_HandleTypeDef *hdcmi) { if(vLineCntFrame++ ==FRAMELINES) { __HAL_DCMI_DISABLE(hdcmi);//this is not safe stop DCMI over DMA, but allows the frame to be stable HAL_DMA_Abort(hdcmi->DMA_Handle); vLineCntFrame=0; pcamera->FlagFrameComplit =1; } }

FRAMELINES – количество строк в кадре (…/User/Inc/camera.h).

Инициализация камеры.

Функция инициализации камеры:

void CameraInit(void) { pcamera->pBufCmdResponse = ResponseCmdFromCam; pcamera->pBufCmdReceived = ReceiveCmdToCam; pcamera->Start = CameraStart; }

Инициализация буферов команд и функции Start.

Структура камеры (…/User/Inc/camera.h):

typedef struct{ uint8_t State;//enable or disable uint8_t CmdFrameComplit;//exec cmd uint32_t AddrBufFrame; volatile uint8_t FlagFrameBufFull; volatile uint8_t FlagFrameComplit; uint8_t FlagFrameTrans; uint32_t cntBufFrame; uint8_t NumBuffs;//number of buffers char *pBufCmdResponse; char *pBufCmdReceived; uint16_t ResponseSize; uint16_t CmdSize; volatile uint8_t FlagCmdResponse; volatile uint8_t FlagCmdReceived; void (* Start) (void); void (* Init) (void); }CameraTypeDef;

Сущность класса CameraTypeDef — Camera;                     //TV — thermal imager

CameraStart (…/User/Src/camera.c):

void CameraStart(void) { HAL_UART_Transmit(&huart2,(uint8_t *)Cmd[CAM_SYCH_MODE_EN],strlen(Cmd[CAM_SYCH_MODE_EN]),100); HAL_Delay(40); HAL_UART_Transmit(&huart2,(uint8_t *)Cmd[CAM_DIG_VIDEO_OUT],strlen(Cmd[CAM_DIG_VIDEO_OUT]),100); }

Камера настраивается по uart, так реализована сама камера.

Выбор команды — CAM_SYCH_MODE_EN (режим синхронизации). Сама команда — rw 99 131\r. rw – внутренняя команда камеры – чтение/запись регистра, параметры – регистр и записываемое значение. Команды и значения записываются в десятичном формате. Т.е. 99 – 0x63 регистр, описание в Astir2 User Guide на стр. 31.

Битовое поле регистра External synchronization mode:

Для понимания:

Режим continuous synchronization mode

Режим continuous synchronization mode
Режим single frame synchronization mode

Режим single frame synchronization mode

Выбран режим continuous.

Выбор команды — CAM_DIG_VIDEO_OUT (цифровой выход). Сама команда — video output 18\r. В Astir2 User Guide это регистр 0x7D стр. 33.

BT656 протокол

Протокол BT656 – параллельный протокол с количеством данных от 8 до 10 и линия клока. В данном проекте используется 8-ми параллельная передача данных.

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

EAV – End Active Video

SAV – Start Active Video

EAV и SAV есть для полезных данных и для Blanking. Определяется по определенному порядку, таблица ниже:

Preamble – 0xFF0000

F – field (четные/нечетные строки): F – 0 – нечетные строки.

V – вертикальная развертка

H = 0 — SAV, H = 1 – EAV

P3 = V + H

P2 = F + H

P1 = F + V

P0 = F + V + H

Настройка кодов синхронизации в программе:

  hdcmi.Init.SyncroCode.FrameEndCode = 0x9d;   hdcmi.Init.SyncroCode.FrameStartCode = 0x80;   hdcmi.Init.SyncroCode.LineStartCode = 0xab;   hdcmi.Init.SyncroCode.LineEndCode = 0xb6;

В продолжении статьи будет освещена настройка USB Custom.

Ссылка на программу


ссылка на оригинал статьи https://habr.com/ru/articles/876552/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *