W5300 을 이용한 네트워크 카메라 구현 1, 2, 3/3
STM32 Board와 W5300 Ethernet module 을 이용한 카메라 이미지 출력 및 영상처리
2
Project description
W5300 을 이용한 네트워크 카메라 구현 1/3 - 기본 개발환경 구성하기
Original link is https://nexp.tistory.com/3043
MCU 선정
W5300의 인터페이스는 Address/Data Bus 방식 이므로 데이터 버스를 제공하고 카메라 인터페이스가 있는 STM32F4 시리즈중 144핀 패키지의 STM32F417Zx를 선정
하드웨어 회로도

STM32의 클럭 설정은 8Mhz의 외부 크리스털로 설정하고 클럭스피드를 최대 168Mhz로 설정해 준다.

설정이 끝나고 저장하면 자동으로 기본 동작 코드가 생성

W5300제어용 FSMC 설정
W5300은 STM32의 FSMC를 통해 제어 되므로 FSMC 설정이 필요

W5300의 CS 핀은 PG9->FSMC_NE2에 연결되어 있고 0x64000000 어드레스 에서 제어
FMC 어드레스 할당 핀맵
(BANK1)CS1 -> PD7 : ((uint32_t)0x60000000)
(BANK2)CS2 -> PG9 : ((uint32_t)0x64000000)
(BANK3)CS3 -> PG10 : ((uint32_t)0x68000000)
(BANK4)CS4 -> PG12 : ((uint32_t)0x6C000000)
W5300 을 이용한 네트워크 카메라 구현 2/3 - TCP 전송률 테스트
Original link is https://nexp.tistory.com/3044
Wiznet ioLibrary Driver 포팅 및 TCP Loopback 전송률 테스트
W5300 테스트를 위한 [STM32F4-RP] 보드의 기본 개발환경 설정이 완료 되었다면 다운로드 받은 ioLibrary의 Ethernet 폴더에 W5300관련 코드를 프로젝트에 복사 하고 컴파일

헤더파일의 디렉토리를 찾을수 없다는 에러가 발생

컴파일이 완료 되었다면 ioLibrary를 보드에 맞게 포팅해 주어야 하는데 W5300의 리셋함수, W5300 레지스터 읽기 함수(W5300_read), 쓰기 함수(W5300_write)를 등록
#define W5300_BANK_ADDR ((uint32_t)0x64000000)
#define _W5300_DATA(p) (*(volatile unsigned short*) (W5300_BANK_ADDR + (p<<1)))
void Reset_W5300()
{
HAL_GPIO_WritePin(RESET_W5300_GPIO_Port, RESET_W5300_Pin, GPIO_PIN_RESET);
HAL_Delay(10);
HAL_GPIO_WritePin(RESET_W5300_GPIO_Port, RESET_W5300_Pin, GPIO_PIN_SET);
HAL_Delay(100);
}
void W5300_write(uint32_t addr, iodata_t wd)
{
_W5300_DATA(addr) = wd;
}
iodata_t W5300_read(uint32_t addr)
{
return _W5300_DATA(addr);
}
W5300 TCP Loopback 전송속도 테스트
W5300을 이용하여 TCP loopback 테스트를 하기 위해 loopback.c 파일을 사용하면 된다.
먼저 네트워크 환경을 wiz_NetInfo 구조체에 할당하고 초기화 코드를 작성해 준다.
wiz_NetInfo gWIZNETINFO = {
.mac = {0x00, 0x08, 0xdc, 0, 0, 0},
.ip = {172, 30, 1, 104},
.sn = {255, 255, 0, 0},
.gw = {172, 30, 1, 254},
.dns = {0, 0, 0, 0},
.dhcp = NETINFO_STATIC
};
void Reset_W5300()
{
HAL_GPIO_WritePin(RESET_W5300_GPIO_Port, RESET_W5300_Pin, GPIO_PIN_RESET);
HAL_Delay(10);
HAL_GPIO_WritePin(RESET_W5300_GPIO_Port, RESET_W5300_Pin, GPIO_PIN_SET);
HAL_Delay(100);
}
void _InitW5300(void)
{
unsigned int tmpaddr[4];
Reset_W5300();
reg_wizchip_bus_cbfunc(W5300_read, W5300_write);
printf("getMR() = %04X\r\n", getMR());
if (ctlwizchip(CW_INIT_WIZCHIP, (void*)wiznet_memsize) == -1)
{
printf("W5300 memory initialization failed\r\n");
}
ctlnetwork(CN_SET_NETINFO, (void *)&gWIZNETINFO);
print_network_information();
}
최적화
네트워크 전송 속도를 높이려면 W5300에 데이터를 최대한 빨리 읽고 써야 하는데 w5300.c 파일에 있는 WIZCHIP_WRITE(), WIZCHIP_READ() 함수를 수정
아래 코드와 같이 수정하면 함수 포인터를 거치는 지연없이 바로 메모리에 접근 할 수 있다.
이부분을 DMA를 사용하면 좀더 성능을 개선할 수 있을것 같다.
WIZCHIP_WRITE() 함수

WIZCHIP_READ() 함수

최적화 전

최적화 후

W5300 을 이용한 네트워크 카메라 구현 3/3 - 카메라 이미지 출력 및 영상처리
Original link is https://nexp.tistory.com/3047
STM32의 카메라 인터페이스 DCMI를 이용하여 카메라 영상을 얻어 네트워크로 이미지 영상을 보내고 PC 호스트 프로그램에서 영상을 받아서 간단히 영상 처리 할수 있는 프로그램을 작성
카메라 연결
STM32에서 카메라는 DCMI 장치에서 설정 할 수 있다. STM32CubeIDE 를 이용하여 DCMI설정을 해 준다.

인터럽트를 사용할 수 있도록 설정하고 DMA 설정도 해 준다.
FIRMWARE
카메라 제어 관련 코드는 STMicro에서 제공하는 ov2640.c 파일(https://github.com/STMicroelectronics/stm32-ov2640) 을 이용하였다.
카메라 관련 함수는 _user_code_cam.h 에 작성되어 있다.
카메라에서 라인데이터가 들어올 때 HAL_DCMI_LineEventCallback() 함수와 한프레임이 완료 되었을때 HAL_DCMI_VsyncEventCallback() 함수를 재 정의 해서 main 함수에 알려 주도록 했다.
void HAL_DCMI_LineEventCallback(DCMI_HandleTypeDef *hdcmi)
{
gCameraLineFlag++;
}
void HAL_DCMI_VsyncEventCallback(DCMI_HandleTypeDef *hdcmi)
{
gCameraFrameFlag++;
}
void CamImagTransferLine(unsigned int Cmd, unsigned int Para)
{
int ret ;
unsigned char data_buf[2048*_UDP_TX_BUF_RATE];
unsigned int size = _IMAGE_SIZE_X*2*_UDP_TX_BUF_RATE;
data_buf[0] = Cmd;
data_buf[1] = 0;
data_buf[2] = Para>>8;
data_buf[3] = Para;
memcpy((uint8_t *)&data_buf[4], (uint8_t *)&FrameBuffer, size);
if(gImgTransferFlag)
{
ret = send(_CAM_SOCK_NUM, (uint8_t *)data_buf, size+4);
}
}
void CamImagTransferFrame(unsigned int Cmd, unsigned int Para)
{
int ret ;
unsigned char data_buf[2048*_UDP_TX_BUF_RATE];
unsigned int size = _IMAGE_SIZE_X*2*_UDP_TX_BUF_RATE;
data_buf[0] = Cmd;
data_buf[1] = 0;
data_buf[2] = Para>>8;
data_buf[3] = Para;
if(gImgTransferFlag)
{
HAL_Delay(1);
ret = send(_CAM_SOCK_NUM, data_buf, size+4);
HAL_Delay(1);
}
}
메인 루프에서 라인 인터럽트 신호가 인식되면 카메라 버퍼에 저장되어 있는 영상 데이터를 TCP 로 전송하고 프레임 인터럽트 신호가 인식되면 PC 호스트 프로그램에 프레임 완료 신호를 전송해서 화면을 갱신하도록 했다.
while (1)
{
/* USER CODE END WHILE */
ProcessCamTcps(_CAM_SOCK_NUM, ethBuf0, dDestport);
if(gCameraFrameFlag>0)
{
gCameraFrameFlag = 0;
CamImagTransferFrame(_CMD_CAM_FRAME, gLineCnt);
printf(">%d, %d\r\n", gFrameCnt, gLineCnt);
gFrameCnt++;
gLineCnt = 0;
}
if(gCameraLineFlag>0)
{
gCameraLineFlag = 0;
CamImagTransferLine(_CMD_CAM_LINE, gLineCnt);
gLineCnt++;
}
/* USER CODE BEGIN 3 */
}
