본문 바로가기

Firmware/stm32

OV5642_LWIP_RTOS Project -1

OV5642 카메라 데이터를 LWIP와 RTOS를 활용하여 Software에 보내는 프로젝트

 

----------------------------------------------------------------------------------------------------------

LWIP Version : 2.1.2

 

FreeRTOS version: 10.2.1

CMSIS-RTOS version: 2.00

 

STM32CubeMX Version: 5.6.1

 

Firmware Version: STM32Cube_FW_F4_V1.25.0

 

MCU: STM32F407VET

----------------------------------------------------------------------------------------------------------

 

LWIP 설정

TCP Buffer Size는 컴퓨터에서 받을 수있는 최고 size (2920Bytes)를 중심으로 계산하여 만들었다.

 

이전에 LWIP RAW API를 활용하여 개발 하였을 때 문제 없이 사용하였다.

 

주의!!

LWIP_NETIF_STATUSCALLBACK OPTION은 Firmware Version에 따라 CMSIS-V1으로 만들어져서 컴파일이 안되는 경우가 있었다. Version 확인 필수

 

Task 종류

기본 Idle Task라고 할 수 있는 defaultTask와 그 외 TcpTask, CameraTask를 만들었다.

 

아직은 priority 와 Parameter 그리고 Task Switching 하기위한 semaphre나 Mutexes는 설정하지 않았다.

 

Main.c

int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_I2C1_Init();
  MX_SPI3_Init();
  /* USER CODE BEGIN 2 */

  /* USER CODE END 2 */

  /* Init scheduler */
  osKernelInitialize();  /* Call init function for freertos objects (in freertos.c) */
  MX_FREERTOS_Init(); 
  /* Start scheduler */
  osKernelStart();
 
  /* We should never get here as control is now taken by the scheduler */
  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

 

StartDefaultTask

void StartDefaultTask(void *argument)
{
  /* init code for LWIP */
  MX_LWIP_Init();
  /* USER CODE BEGIN StartDefaultTask */
  /* Infinite loop */
  for(;;)
  {
    osDelay(100);
  }
  /* USER CODE END StartDefaultTask */
}

CubeMX로 Code 생성 시 MX_LWIP_Init이 생성된다.

 

MX_LWIP_Init

void MX_LWIP_Init(void)
{
  /* IP addresses initialization */
  IP_ADDRESS[0] = 192;
  IP_ADDRESS[1] = 168;
  IP_ADDRESS[2] = 1;
  IP_ADDRESS[3] = 111;
  NETMASK_ADDRESS[0] = 255;
  NETMASK_ADDRESS[1] = 255;
  NETMASK_ADDRESS[2] = 255;
  NETMASK_ADDRESS[3] = 0;
  GATEWAY_ADDRESS[0] = 192;
  GATEWAY_ADDRESS[1] = 168;
  GATEWAY_ADDRESS[2] = 1;
  GATEWAY_ADDRESS[3] = 1;
  
  /* Initilialize the LwIP stack with RTOS */
  tcpip_init( NULL, NULL );

  /* IP addresses initialization without DHCP (IPv4) */
  IP4_ADDR(&ipaddr, IP_ADDRESS[0], IP_ADDRESS[1], IP_ADDRESS[2], IP_ADDRESS[3]);
  IP4_ADDR(&netmask, NETMASK_ADDRESS[0], NETMASK_ADDRESS[1] , NETMASK_ADDRESS[2], NETMASK_ADDRESS[3]);
  IP4_ADDR(&gw, GATEWAY_ADDRESS[0], GATEWAY_ADDRESS[1], GATEWAY_ADDRESS[2], GATEWAY_ADDRESS[3]);

  /* add the network interface (IPv4/IPv6) with RTOS */
  netif_add(&gnetif, &ipaddr, &netmask, &gw, NULL, &ethernetif_init, &tcpip_input);

  /* Registers the default network interface */
  netif_set_default(&gnetif);

  if (netif_is_link_up(&gnetif))
  {
    /* When the netif is fully configured this function must be called */
    netif_set_up(&gnetif);
  }
  else
  {
    /* When the netif link is down this function must be called */
    netif_set_down(&gnetif);
  }

  /* Set the link callback function, this function is called on change of link status*/
  netif_set_link_callback(&gnetif, ethernetif_update_config);

  /* create a binary semaphore used for informing ethernetif of frame reception */
  Netif_LinkSemaphore = osSemaphoreNew(1, 1, NULL);

  link_arg.netif = &gnetif;
  link_arg.semaphore = Netif_LinkSemaphore;
  /* Create the Ethernet link handler thread */
/* USER CODE BEGIN OS_THREAD_NEW_CMSIS_RTOS_V2 */
  memset(&attributes, 0x0, sizeof(osThreadAttr_t));
  attributes.name = "LinkThr";
  attributes.stack_size = INTERFACE_THREAD_STACK_SIZE;
  attributes.priority = osPriorityBelowNormal;
  osThreadNew(ethernetif_set_link, &link_arg, &attributes);
/* USER CODE END OS_THREAD_NEW_CMSIS_RTOS_V2 */

/* USER CODE BEGIN 3 */

/* USER CODE END 3 */
}

MX_LWIP_Init 에서는 IP 설정 후 thread를 생성하여  주기적으로 호출하는데 이 Thread는 Ethernet Cable이 연결되었는지 주기적으로 검사하는 Thread이다.

 

만약 연결이 되지 않았다면 netif_set_down을 호출하여 연결을 Disconnect 하고

 

연결이 되었다면 netif_set_up을 호출하여 Ethernet을 연결한다.

 

앞서 CubeMx에서 언급한 NETIF_CALLBACK 기능을 끄면 위 Thread는 생성되지 않으며 MX_LWIP_Init함수를 호출 할때 

 

Cable이 연결 되어 있지 않으면 연결 후 다시 재부팅하여 MX_LWIP_Init 함수를 호출 해줘야 연결이 된다.

 

TCP_Task

void Tcp_Task(void *argument)
{
  /* USER CODE BEGIN Tcp_Task */
  struct netconn *conn, *newconn;
  err_t err, accept_err;
  struct netbuf *buf;
  void *data;
  u16_t len;
  
  LWIP_UNUSED_ARG(argument);
  
  conn = netconn_new(NETCONN_TCP);
  
  if (conn!=NULL)
  {  
    err = netconn_bind(conn, NULL, 1460);
    
    if (err == ERR_OK)
    {
      netconn_listen(conn);
      
      while (1) 
      {
        accept_err = netconn_accept(conn, &newconn);
        
        if (accept_err == ERR_OK) 
        {
          
          while (netconn_recv(newconn, &buf) == ERR_OK) 
          {
            do 
            {
              netbuf_data(buf, &data, &len);
              netconn_write(newconn, data, len, NETCONN_COPY);
              
            } 
            while (netbuf_next(buf) >= 0);
            
            netbuf_delete(buf);
          }
          netconn_close(newconn);
          netconn_delete(newconn);
        }
        
       osDelay(100);
      }
    }
    else
    {
      netconn_delete(newconn);
    }
    
   
  }
  
  
  
  /* Infinite loop */

  /* USER CODE END Tcp_Task */
}

 기본적인 구현은 CubeMX를 따라 구현 하였다. 일반적인 Socket Programming과 크게 다르지 않다.

 

 

bind,listen,accept 함수 앞에 netconn만 붙이면 위 소스와 흐름이 똑같다.

 

실제 구현 후 동작 화면