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/


Интересные статьи

Интересные статьи

Всем привет, случалось такое, что вам надо поставить кучу агентов битрикса на крон, а потом сидеть и разбираться - сколько они отрабатывают, отрабатывают ли вообще, когда падают или зависают? Ну конеч...
Есть такие, кто считает, что нет оснований для использования отдельного понятия архитектор 1С. Дескать, архитекторы это, например, Растрелли или Гауди, а мы тут немного другим занимаемся. Разработ...
Статья о том, как упорядочить найм1. Информируем о вакансии2. Ведём до найма3. Автоматизируем скучное4. Оформляем и выводим на работу5. Отчитываемся по итогам6. Помогаем с адаптацией...
Много всякого сыпется в мой ящик, в том числе и от Битрикса (справедливости ради стоит отметить, что я когда-то регистрировался на их сайте). Но вот мне надоели эти письма и я решил отписатьс...
Первая цифровая фотокамера у меня появилась 14 назад. Тогда же возникла и проблема хранения фотографий. К счастью, в то время она решалась быстро и однозначно — записать на диск, и точка. Внешн...