[ST_MICRO]/STM32H72018. 12. 6. 05:33

STMH7 EVM - USB Mass Storage Host Mode 테스트


STMH7 EVM - USB Mass Storage Host Mode 테스트





STM32H7 EVM 보드에는 USB Host 및 Device를 테스트 할 수 있는 커넥터가 있다.


CubeMX로 USB HOST 모드 설정







USB_HOST 모드설정을 Mass Storage Host Class 로 설정한다.

VBUS 파워 공급을 GPIO로 설정 할 수도 있지만 이번에는 그냥 하드웨어 적으로 Host Mode 고정으로 전원을 강제로 공급하도록 했다.






CubeMX에서  FATFS 설정은 USB Disk로 설정한다.






이렇게 CubeMX 설정으로 마무리 하여 코드를 생성하면 대부분 자동으로 생성이 된다.

생성된 코드에서 수정 할 부분을 usb_host.c 파일의 USBH_UserProcess() 함수에 추가하면 된다.


main 함수에서 주기적으로 수행하면서 처리되는 함수 인데 테스트를 위해 HOST_USER_CLASS_ACTIVE 이벤트에서 디렉토리 내용을 출력하도록 했다.

static void USBH_UserProcess  (USBH_HandleTypeDef *phost, uint8_t id)
{
  /* USER CODE BEGIN CALL_BACK_1 */
  switch(id)
  {
         case HOST_USER_SELECT_CONFIGURATION:
                printf("CONFIGURATION\r\n");
                break;
         case HOST_USER_DISCONNECTION:
                Appli_state = APPLICATION_DISCONNECT;
 
                printf("DISCONNECTION\t\n");
                break;
         case HOST_USER_CLASS_ACTIVE:
                Appli_state = APPLICATION_READY;
                printf("APPLICATION_READY\r\n");

                f_opendir_scan_usb();
                break;
         case HOST_USER_CONNECTION:
                Appli_state = APPLICATION_START;
                printf("CONNECTION\r\n");
                break;
  default:
  break;
  }
  /* USER CODE END CALL_BACK_1 */

}




void f_opendir_scan_usb(void)
{
    DIR dir;
       FILINFO fno;
    TCHAR path[200] = "0:";

    res = f_mount(&fat32,path,0);
    printf("USB Mount : res f_mount : %d\r\n",res);
    if (res == FR_OK)
    {
    res = f_opendir(&dir,path);
        printf("res f_open : %02X\n\r",res);
        if (res == FR_OK)
        {
        while(1)
        {
            char *fn;
            res = f_readdir(&dir, &fno);
            if (res != FR_OK)
                printf("res = %d f_readdir\n\r", res);
            if ((res != FR_OK) || (fno.fname[0] == 0))
                break;
      */
      fn = fno.fname;
            printf("%c%c%c%c ",
                ((fno.fattrib & AM_DIR) ? 'D' : '-'),
                ((fno.fattrib & AM_RDO) ? 'R' : '-'),
                ((fno.fattrib & AM_SYS) ? 'S' : '-'),
                ((fno.fattrib & AM_HID) ? 'H' : '-') );
            printf("%10d ", fno.fsize);
            printf("%s/%s\n\r", path, fn);
        }
        }
        res = f_mount(0,path,0);
        printf("USB Unmount : res f_mount : %02X\n\r",res);
    }

}


테스트 해 보면 STM32H7 EVM 보드에 USB 메모리 스틱을 연결하면 인식해서 메모리 스틱의 파일 목록을 보여 주고 있다.




Posted by nexp

댓글을 달아 주세요

[ST_MICRO]/STM32H72018. 12. 4. 02:02

STM32H7 CubeMx SD Card Test

STM32H7 CubeMx SD Card Test


[STM32H7 EVM] 보드에는 4bit SD 인터페이스가 있어 SD카드 FAT 연결 테스트를 Stm32CubeMx를 이용하여 해 보았다.


우선 SD카드는 하드웨어 적으로 STM32H7의 디폴트 SDMMC1에 연결되어 있다.


STM32H7 EVM보드는에 아래면에 SD소켓이 장착되어 있다.







STM32CubeMx 를 이용하여 SDMMC1을 SD 4bit 모드로 선택한다.






Middleware 탭의 FATFS에서 Mode를 SD Card로 선택 한다.




이렇게 해서 기본으로 코드 생성하면 아래와 같은 코드가 생성 되는데... 



주의 해야 할 사항은 bsp_driver_sd.c 파일에 있는 BSP_SD_Init() 함수를 호출 해 주어야 한다는 것이다.


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_TIM3_Init();
  MX_USART1_UART_Init();
  MX_SDMMC1_SD_Init();
  MX_FATFS_Init();
  /* USER CODE BEGIN 2 */
  BSP_SD_Init();
  /* USER CODE END 2 */
  //disk_initialize((BYTE) 0);
  f_opendir_scan_sd();
  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */
    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */

}




SD를 4bit 모드로 변환 해 주는 부분이다.


uint8_t BSP_SD_Init(void)
{
  uint8_t sd_state = MSD_OK;
  /* Check if the SD card is plugged in the slot */
  if (BSP_SD_IsDetected() != SD_PRESENT)
  {
    return MSD_ERROR_SD_NOT_PRESENT;
  }
  /* HAL SD initialization */
  sd_state = HAL_SD_Init(&hsd1);
  /* Configure SD Bus width (4 bits mode selected) */
  if (sd_state == MSD_OK)
  {
    /* Enable wide operation */
    if (HAL_SD_ConfigWideBusOperation(&hsd1, SDMMC_BUS_WIDE_4B) != HAL_OK)
    {
      sd_state = MSD_ERROR;
    }
  }
  return sd_state;

}






SD 카드 읽어 파일 내용을 출력 해주면 쉽게 SD카드 테스트 완료


void f_opendir_scan_sd(void)

{
    DIR dir;
       FILINFO fno;
    TCHAR path[200] = "0:";

    res = f_mount(&SDFatFS,path,0);
    printf("SD Mount : res f_mount : %02X\n\r",res);
    if (res == FR_OK)
    {
    res = f_opendir(&dir,path);
        printf("res f_open : %02X\n\r",res);
        if (res == FR_OK)
        {
        while(1)
        {
            char *fn;
            res = f_readdir(&dir, &fno);
            if (res != FR_OK)
                printf("res = %d f_readdir\n\r", res);
            if ((res != FR_OK) || (fno.fname[0] == 0))
                break;

      fn = fno.fname;
            printf("%c%c%c%c ",
                ((fno.fattrib & AM_DIR) ? 'D' : '-'),
                ((fno.fattrib & AM_RDO) ? 'R' : '-'),
                ((fno.fattrib & AM_SYS) ? 'S' : '-'),
                ((fno.fattrib & AM_HID) ? 'H' : '-') );
            printf("%10d ", fno.fsize);
            printf("%s/%s\n\r", path, fn);
        }
        }
        res = f_mount(0,path,0);
        printf("SD Unmount : res f_mount : %02X\n\r",res);
    }
}












Posted by nexp

댓글을 달아 주세요

[ST_MICRO]/STM32H72018. 12. 4. 02:01

STM32H7 EVM - 이더넷 테스트 (TCP/IP전송 속도 테스트)

STM32H7 EVM - 이더넷 테스트 (TCP/IP전송 속도 테스트)




STM32H743의 경우 100핀 페키지에 이더넷을 지원하고 480Mhz로 동작 하기 때문에 작은 사이즈에 고성능 이더넷이 필요한 어플리케이션에 사용하기에 좋을것 같다.





STM32H7 EVM 보드에는 Ethernet PHY 모듈을 연결할 수 있어 STM32H7 의 Ethernet을 연결을 할 수 있다.





Ethernet PHY 모듈 핀맵





먼저 STM32CubeMx 로  Connectivity -> ETH 탭에서 RMII 모드로 설정해 준다. 




Middleware -> LWIP 탭에서 TCP/IP stack 를 설정해야 하는데... 

활성화가 안되어 있다. SYS탭에서 DCache를 Enable 해야 활성화가 된다.






DCashe 도 설정 해 주어야 한다고 한다.




이렇게 CubeMx로 Ethernet 설정을 하면 자동 생성 코드로 코드가 생성되지만 STM32F7 EVM 보드에서 테스트 한 동일한 코드가 정상 동작을 하지 않는다.


int main(void)
{
  /* USER CODE BEGIN 1 */
  /* USER CODE END 1 */
 
  /* MPU Configuration--------------------------------------------------------*/
  MPU_Config();
  /* Enable I-Cache---------------------------------------------------------*/
  SCB_EnableICache();
  /* Enable D-Cache---------------------------------------------------------*/
  //SCB_EnableDCache();
  /* 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_USART1_UART_Init();
  //MX_SDMMC1_SD_Init();
  MX_LWIP_Init();
  /* USER CODE BEGIN 2 */
  /* USER CODE END 2 */
  printf("SysClk (System Clock) = %lu Hz\r\n", HAL_RCC_GetSysClockFreq());
  while((gnetif.ip_addr.addr) == 0)
  {
         MX_LWIP_Process();
  }
  print_ip_settings(&gnetif.ip_addr.addr, &gnetif.netmask.addr, &gnetif.gw.addr);
  tcp_echoserver_init();
  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
           MX_LWIP_Process();
    /* USER CODE END WHILE */
    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}





CubeMx에서 생성한 다른 코드들은 STM32F7 과 동일하게 동작하는데... 왜 이더넷 코드는 정상 동작을 하지 않을까?

ST제공 예제를 좀 찾아 보니 MCU_Config() 함수에 Ehernet 영역을 설정을 해 주어야 한다고 한다. 그리고 링크스크립트 파일도 수정이 필요 하다.


void MPU_Config(void)

{
         MPU_Region_InitTypeDef MPU_InitStruct;
         /* Disable the MPU */
         HAL_MPU_Disable();
         /* Configure the MPU attributes as Device not cacheable
            for ETH DMA descriptors */
         MPU_InitStruct.Enable = MPU_REGION_ENABLE;
         MPU_InitStruct.BaseAddress = 0x30040000;
         MPU_InitStruct.Size = MPU_REGION_SIZE_256B;
         MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
         MPU_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE;
         MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE;
         MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE;
         MPU_InitStruct.Number = MPU_REGION_NUMBER0;
         MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;
         MPU_InitStruct.SubRegionDisable = 0x00;
         MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;
         HAL_MPU_ConfigRegion(&MPU_InitStruct);
         /* Configure the MPU attributes as Cacheable write through
            for LwIP RAM heap which contains the Tx buffers */
         MPU_InitStruct.Enable = MPU_REGION_ENABLE;
         MPU_InitStruct.BaseAddress = 0x30044000;
         MPU_InitStruct.Size = MPU_REGION_SIZE_16KB;
         MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
         MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;
         MPU_InitStruct.IsCacheable = MPU_ACCESS_CACHEABLE;
         MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE;
         MPU_InitStruct.Number = MPU_REGION_NUMBER1;
         MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;
         MPU_InitStruct.SubRegionDisable = 0x00;
         MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;
         HAL_MPU_ConfigRegion(&MPU_InitStruct);
         /* Enable the MPU */
         HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);
}




우여곡절 끝에 STM32H7에서 이더넷 동작이 정상적으로 된다. DHCP로 IP도 잘 받아오고 TCP 전송도 잘 동작한다.


하지만 고속으로 TCP 루프백 테스트를 해 보면 오류가 발생한다. 






여러가지 설정도 바꿔 보고 메모리 메모리도 키워보고 해도 동일한 현상이 반복된다.

STM32CubeIDE를 이용하면 좀 달라 질까 싶어 테스트 해 보았지만... 에러 빈도가 줄어 들긴 하지만 여전히 전송 에러가 발생하고 있다. 동일한 Ehternet PHY 모듈을 STM32F7 보드에서 구동 시키면 문제 없이 잘 동작하는것으로 보아 하드웨어는 문제 없어 보인다.


STM32F7 EVM 보드에서 TCP전송 속도 테스트 결과와 비교 해 보면 비슷한 수준이지만 에러가 자주 발생해서 이문제를 해결해야 할것 같다.



STM32H7의 향상된 CPU속도로 이더넷 성능도 좋아 졌을거라 기대를 하고 테스트 했는데... 

결론적으로는 이더넷에 문제가 있는것 같다. 좀 더 들여달 볼 필요가 있을것 같다.

Posted by nexp

댓글을 달아 주세요

[ST_MICRO]/STM32H72018. 12. 4. 02:01

STM32H7 Timer 테스트 - 1초 만들기 (내부 클럭 vs 외부클럭)

STM32H7 Timer 테스트 - 1초 만들기 (내부 클럭 vs 외부클럭)



별다른 기능이 없는 TIMER6을 사용하여 테스트 해 보자

CubeMX 에서 세팅





인터럽트 체크하고...





생성된 코드에서 stm32h7xx_it.c파일을 보면 TIM6_DAC_IRQHandler()가 생성되어 있고 인터럽트 발생시 마다 HAL_TIM_IRQHandler() 함수를 호출한다.


void TIM6_DAC_IRQHandler(void)

{
  /* USER CODE BEGIN TIM6_DAC_IRQn 0 */
  /* USER CODE END TIM6_DAC_IRQn 0 */
  HAL_TIM_IRQHandler(&htim6);
  /* USER CODE BEGIN TIM6_DAC_IRQn 1 */
  /* USER CODE END TIM6_DAC_IRQn 1 */
}




stm32h7xx_hal_tim.c 파일에서 HAL_TIM_PeriodElapsedCallback() 함수를 호출하는 구조이므로 HAL_TIM_PeriodElapsedCallback()를 재 정의 해 주면된다.


void HAL_TIM_IRQHandler(TIM_HandleTypeDef *htim)

{
  /* TIM Update event */
  if (__HAL_TIM_GET_FLAG(htim, TIM_FLAG_UPDATE) != RESET)
  {
    if (__HAL_TIM_GET_IT_SOURCE(htim, TIM_IT_UPDATE) != RESET)
    {
      __HAL_TIM_CLEAR_IT(htim, TIM_IT_UPDATE);
#if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)
      htim->PeriodElapsedCallback(htim);
#else
      HAL_TIM_PeriodElapsedCallback(htim);
#endif /* USE_HAL_TIM_REGISTER_CALLBACKS */
    }
  }
}





메인 함수에서는 HAL_TIM_Base_Start_IT() 함수로 타이머 구동 시켜주면 인터럽트 발생시 마다 HAL_TIM_PeriodElapsedCallback() 함수가 수행된다.


  MX_TIM6_Init();
  /* USER CODE BEGIN 2 */
  /* USER CODE END 2 */
 
  HAL_TIM_Base_Start_IT(&htim6) ;
  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */
    /* USER CODE BEGIN 3 */
  }



void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
       //HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5) ;
       GPIOA->ODR ^= GPIO_PIN_5;
}



STM32H7의 타아머는 200Mhz 로 동작하고 프리스캐일을 200으로 설정하면 1us마다 인터럽트를 동작 시킬 수 있다.

200 000000 / 200 = 1Mhz -> 1us

오토리로드 값을 1000으로 설정하면 1ms 마다 인터럽트를 발생시키고 PA5를 토글 시켜 확인이 가능하다.




동작 시켜보면 1ms 정도 나오긴 하는데... 1.062ms 이다.
이상하네...





GPIO토글 할 때 함수를 호출해서 그런가?

레지스터를 직접 제어 해 보면...
GPIOA->ODR ^= GPIO_PIN_5;

별 차이가 없다. 1ms 정도면 빠른 속도가 아니라 차이는 없어 보이는데....

클럭의 문제가 아닐까?

HSI로 설정해서 테스트 했었는데 HSE(25Mhz)로 해 보자







클럭을 외부 클럭으로 바꾸니 정확히 1ms로 구동이 된다.

(타이밍이 중요한 프로젝트에서는 외부클럭이 꼭 필요할 것 같다.)



STM32H7 HSE 25Mhz로 400Mhz 구동 설정 코드


void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
  RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0};
  /** Supply configuration update enable
  */
  HAL_PWREx_ConfigSupply(PWR_LDO_SUPPLY);
  /** Configure the main internal regulator output voltage
  */
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
  while(!__HAL_PWR_GET_FLAG(PWR_FLAG_VOSRDY)) {}
  /** Initializes the CPU, AHB and APB busses clocks
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLM = 5;
  RCC_OscInitStruct.PLL.PLLN = 160;
  RCC_OscInitStruct.PLL.PLLP = 2;
  RCC_OscInitStruct.PLL.PLLQ = 2;
  RCC_OscInitStruct.PLL.PLLR = 2;
  RCC_OscInitStruct.PLL.PLLRGE = RCC_PLL1VCIRANGE_2;
  RCC_OscInitStruct.PLL.PLLVCOSEL = RCC_PLL1VCOWIDE;
  RCC_OscInitStruct.PLL.PLLFRACN = 0;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }
  /** Initializes the CPU, AHB and APB busses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2
                              |RCC_CLOCKTYPE_D3PCLK1|RCC_CLOCKTYPE_D1PCLK1;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.SYSCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_HCLK_DIV2;
  RCC_ClkInitStruct.APB3CLKDivider = RCC_APB3_DIV2;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_APB1_DIV2;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_APB2_DIV2;
  RCC_ClkInitStruct.APB4CLKDivider = RCC_APB4_DIV2;
  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
  {
    Error_Handler();
  }
  PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_HRTIM1|RCC_PERIPHCLK_USART1;
  PeriphClkInitStruct.Usart16ClockSelection = RCC_USART16CLKSOURCE_D2PCLK2;
  PeriphClkInitStruct.Hrtim1ClockSelection = RCC_HRTIM1CLK_TIMCLK;
  if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK)
  {
    Error_Handler();
  }
  HAL_RCC_MCOConfig(RCC_MCO1, RCC_MCO1SOURCE_PLL1QCLK, RCC_MCODIV_4);

}



//HSI 구동시
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
  RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0};
  /** Supply configuration update enable
  */
  HAL_PWREx_ConfigSupply(PWR_LDO_SUPPLY);
  /** Configure the main internal regulator output voltage
  */
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
  while(!__HAL_PWR_GET_FLAG(PWR_FLAG_VOSRDY)) {}
  /** Initializes the CPU, AHB and APB busses clocks
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_DIV1;
  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
  RCC_OscInitStruct.PLL.PLLM = 4;
  RCC_OscInitStruct.PLL.PLLN = 50;
  RCC_OscInitStruct.PLL.PLLP = 2;
  RCC_OscInitStruct.PLL.PLLQ = 2;
  RCC_OscInitStruct.PLL.PLLR = 2;
  RCC_OscInitStruct.PLL.PLLRGE = RCC_PLL1VCIRANGE_3;
  RCC_OscInitStruct.PLL.PLLVCOSEL = RCC_PLL1VCOWIDE;
  RCC_OscInitStruct.PLL.PLLFRACN = 0;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }
  /** Initializes the CPU, AHB and APB busses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2
                              |RCC_CLOCKTYPE_D3PCLK1|RCC_CLOCKTYPE_D1PCLK1;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.SYSCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_HCLK_DIV2;
  RCC_ClkInitStruct.APB3CLKDivider = RCC_APB3_DIV2;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_APB1_DIV2;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_APB2_DIV2;
  RCC_ClkInitStruct.APB4CLKDivider = RCC_APB4_DIV2;
  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
  {
    Error_Handler();
  }
  PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_USART1;
  PeriphClkInitStruct.Usart16ClockSelection = RCC_USART16CLKSOURCE_D2PCLK2;
  if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK)
  {
    Error_Handler();
  }
  HAL_RCC_MCOConfig(RCC_MCO1, RCC_MCO1SOURCE_PLL1QCLK, RCC_MCODIV_8);

}





Posted by nexp
TAG STM32H7

댓글을 달아 주세요

[ST_MICRO]/STM32H72018. 12. 1. 04:54

STM32H7 FMC - TFT LCD 출력하기 (STM32F7 FMC와 다른점)

STM32H7 FMC - TFT LCD 출력하기 (STM32F7 FMC와 다른점)




STM32H7 EVM 보드에는 FMC를 이용하여 기존에 제작 해 두었던 TFT LCD 모듈을 연결할 수 있도록 구성하였다. STM32H7에서 FMC로 TFC LCD 테스트를 진행 해 볼 수 있다.







STM32H7 의 FMC는  Data(16), WR, RD, CS, A16 핀을 할당 할 수 있다.

메모리 맵핑은 기존 STM32 시리즈와 동일하게 0x6000 0000 에 가능하다.






STM32CubeMX에서 FMC 설정을 LCD Interface 타입으로 설정하여 코드 생성 한다.








STM32H7 FMC 기본 동작 테스트

FMC 제어를 위해 STM32CubeMx의 HAL 라이브러리가 제공된다.


uint8_t BSP_SRAM_WriteData(uint32_t uwStartAddress, uint16_t *pData, uint32_t uwDataSize)
{
  if(HAL_SRAM_Write_16b(&hsram1, (uint32_t *)uwStartAddress, pData, uwDataSize) != HAL_OK)
  {
    return SRAM_ERROR;
  }
  else
  {
    return SRAM_OK;
  }

}



스코프 확인식 신호가 정상 적으로 출력 되는것을 확이 할 수 있다.


  MX_FMC_Init();

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
         data ^= 0x55;
         addr ^= 1;
         if(addr)
         {
                //BSP_SRAM_WriteData(LCD_BANK_ADDR, &data, 1);
                _LCD_DATA(0) ^= data ;
         }
         else
         {
                //BSP_SRAM_WriteData(LCD_BANK_ADDR+(1<<16), &data, 1);
                _LCD_DATA((1<<16)) ^= data ;
         }
      
        GPIOD->ODR ^= GPIO_PIN_13;
        HAL_Delay(100);

  }





이제 실제 TFT LCD모듈을 연결하여 테스트 해 보자





TFT LCD가 정상 동작을 하지 않는다.


스코프 확인 해 보니 Address, Data Write 구간에 CS핀이 4번 정도 High가 되는 현상이 있다.





너무 고속이라 그런가?

STM32H7에서 FMC에서 달라진 점은 속도 이다. 최대 180Mhz 까지 가능하다.





열심히 구글링 결과  STM32H7 vs STM32F7 GPIO 속도 테스트2 와 같이 STM32H7의 버스 메트릭스 구조가 달라져서 그1사이클에 4번의 전환이 발생 한다고 한다. H7으로 코드 전환이 쉽지가 않네...


Memory Type을 바꾸어 보니 그런 현상이 없어 졌다.

 hsram1.Init.MemoryType = FMC_MEMORY_TYPE_NOR;




/* FMC initialization function */
static void MX_FMC_Init(void)
{
  /* USER CODE BEGIN FMC_Init 0 */
  /* USER CODE END FMC_Init 0 */
  FMC_NORSRAM_TimingTypeDef Timing = {0};
  /* USER CODE BEGIN FMC_Init 1 */
  /* USER CODE END FMC_Init 1 */
  /** Perform the SRAM1 memory initialization sequence
  */
  hsram1.Instance = FMC_NORSRAM_DEVICE;
  hsram1.Extended = FMC_NORSRAM_EXTENDED_DEVICE;
  /* hsram1.Init */
  hsram1.Init.NSBank = FMC_NORSRAM_BANK1;
  hsram1.Init.DataAddressMux = FMC_DATA_ADDRESS_MUX_DISABLE;
  //hsram1.Init.MemoryType = FMC_MEMORY_TYPE_SRAM;
  hsram1.Init.MemoryType = FMC_MEMORY_TYPE_NOR;
  hsram1.Init.MemoryDataWidth = FMC_NORSRAM_MEM_BUS_WIDTH_16;
  hsram1.Init.BurstAccessMode = FMC_BURST_ACCESS_MODE_DISABLE;
  hsram1.Init.WaitSignalPolarity = FMC_WAIT_SIGNAL_POLARITY_LOW;
  hsram1.Init.WaitSignalActive = FMC_WAIT_TIMING_BEFORE_WS;
  hsram1.Init.WriteOperation = FMC_WRITE_OPERATION_ENABLE;
  hsram1.Init.WaitSignal = FMC_WAIT_SIGNAL_DISABLE;
  hsram1.Init.ExtendedMode = FMC_EXTENDED_MODE_DISABLE;
  hsram1.Init.AsynchronousWait = FMC_ASYNCHRONOUS_WAIT_DISABLE;
  hsram1.Init.WriteBurst = FMC_WRITE_BURST_DISABLE;
  hsram1.Init.ContinuousClock = FMC_CONTINUOUS_CLOCK_SYNC_ONLY;
  hsram1.Init.WriteFifo = FMC_WRITE_FIFO_ENABLE;
  hsram1.Init.PageSize = FMC_PAGE_SIZE_NONE;
  /* Timing */
  Timing.AddressSetupTime = 30;
  Timing.AddressHoldTime = 30;
  Timing.DataSetupTime = 25;
  Timing.BusTurnAroundDuration =50;
  Timing.CLKDivision = 0;
  Timing.DataLatency = 0;
  Timing.AccessMode = FMC_ACCESS_MODE_A;
  /* ExtTiming */
  if (HAL_SRAM_Init(&hsram1, &Timing, NULL) != HAL_OK)
  {
    Error_Handler( );
  }
  /* USER CODE BEGIN FMC_Init 2 */
  /* USER CODE END FMC_Init 2 */

}





SD카드 연결하고 BMP 이미지 출력하니 TFT LCD에 BMP이미지가 정상적으로 출력된다.

















Posted by nexp

댓글을 달아 주세요