[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

댓글을 달아 주세요

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

STM32H7 CubeMx를 이용한 PWM출력 테스트 - 1Mhz PWM

STM32H7 CubeMx를 이용한 PWM출력 테스트 - 1Mhz PWM


STM32CubeMx를 실행해 프로젝트 생성후 핀맵 할당한다.

STM32H7_EVM 보드의 TIM2_CH1(PA5)에  PWM출력 되도록 했다.





TIM2에서 PWM 모드 설정해 주면 된다.







STM32H7 CubeMx 프로젝트 생성후 아래와 같이 HAL코드(HAL_TIM_PWM_Start 함수)로 PWM 출력을 시작 할 수 있다.


  HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1);

  //주파수 편경
  TIM2->ARR = 100-1;// 100 x 5ns

  //펄스폭 가변
  TIM2->CCR1 = 50-1;





생성된 코드를 돌려보면 PWM이 2Mhz로 출력이 된다.
뭐가 설정이 잘못 되었나?
APB2 클럭 최대가 100Mhz로 되어 있어 타이머에 100Mhz가 공급될것으로 생각하고 있었는데...
CubeMX에서 클럭 설정 부분을 잘 보니 TIMER의 경우 200Mhz가 공급 된다고 되어 있다.







그러면 ARR레지스터에 100을 입력 하면 2Mhz로 출력이 되는것이 맞는것 같다.
TimeClk
200000000
Prescale
1
클럭당시간
0.000 000 005
ARR값
100
PWM주파수
2000000


PWM을 50단계까지 생각한다면 최대 PWM주파수를 4Mhz까지 출력 가능 할것 같다.

1Mhz로 구동한다면 200단계 정도 인데... 고속 PWM제어에 바로 쓰기는 약간 아쉬움이 있는것 같다.



기존 STM32F0 PWM 출력 테스트와 비교하면 4배 정도(48Mhz->200Mhz 기준) 좋은것 같다.


참고로 STM32F7 PWM 출력 테스트도 비교할 만하다.

Posted by nexp
TAG PWM, STM32H7

댓글을 달아 주세요

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

STM32H7 vs STM32F7 MCU성능 테스트 - FPU 성능테스트

 

STM32H7 vs STM32F7 MCU성능 테스트 - FPU 성능테스트

 

STM32H7 GPIO 토글 속도 테스트 결과에서 STM32H7의 버스 구조의 특성상 GPIO접근에 속도 제한이 있다는 것은 확인 했는데 그렇다면 CPU부하를 걸어 속도 체크를 해 보면 루프 성능을 확인 할수 있을것 같다.

 

FPU를 사용할수 있도록 루트처리 함수를 이용해 수행 속도를 측정해 보았다.

 

#include  <math.h>

 
volatile double sq_result;
int i;
 
  while (1)
  {
         GPIO_TEST_PORT->BSRR = GPIO_TEST_PIN;
         d = 0;
         for(i=0;i<10;i++)
         {
                d += sqrt(2.0);
         }
         GPIO_TEST_PORT->BSRR = (uint32_t)GPIO_TEST_PIN << GPIO_NUMBER;
  }

 

 

 

STM32H7 @400Mhz 에서 루트연산을 10번 계산한 결과 190ns로 측정된다.

 

 

 

STM32CubeIDE 에서 STM32H7 FPU옵션 설정

 

 

 

STM32H7 @480Mhz 에서 루트 10번 계산 결과 135ns

 

 

 


 

 

STM32F7에서는 어떨까?

 

테스트 결과 216Mhz에서 450ns 정도 측정되다.

 

 

 

 

 


 

 

 

그렇다면 STM32F4에서는?
5000ns 정도로 H7에 비해 20배 이상 속도 차이가 발생하고 있다.
 
 
 
STM32F4의 경우 FPUv4 이다.

 

 

 

 

결론적으로 STM32H7이 STM32F4보다는 20배 STM32F7보다는 4배 정도 더 빠른것 같다.

Posted by nexp

댓글을 달아 주세요

[ST_MICRO]/STM32H72018. 11. 29. 02:37

STM32H7 vs STM32F7 GPIO 속도 테스트2 - 문제 해결

STM32H7 vs STM32F7 GPIO 속도 테스트2 - 문제 해결


STM32 H7성능 테스트 하면서 오래동안 고심했던 H7 GPIO 속도 문제가 해결됬다.
STM32F7의 GPIO 토글 속도를 측정하면 8ns 정도 나오는데 STM32H7의 GPIO 토글 속도를 측정해 보면 28ns 정도나온다.


결론은 STM32H7, STM32F7의 하드웨어 구조의 차이에서 오는 문제였다.


우선 STM32F7의 경우 GPIO는 AXI -> AHB (216Mhz) 로 바로 출력이 가능하므로 2 머신 사이클에 제어 가능하다.






STM32F7 Series system architecture 를 보면 F7의 하드웨어 구조를 확인 할 수 있다.






STM32H7 의 경우 GPIO는 AXI AHB -> AHB4(200Mhz) 를 통해 제어 가능하기 때문에 지연이 생긴다고 한다.

그래서 DMA나 인터럽트를 통해 제어 하면 2머신 사이클에 제어 가능하다고 한다.






버스 구조가 복잡한 대신 하드웨어로 처리 해 주는 부분이 많아 코드상의 main 루프에서 접근하면 오히려 더 느리게 나왔던 것이다.


STM32H7의 성능 지표를 확인해 보면 속도 차이를 확인해 볼 수 있다.


Posted by nexp

댓글을 달아 주세요

[ST_MICRO]/STM32H72018. 11. 29. 02:36

STM32H7 클럭설정 - HSI, HSE 480Mhz

STM32H7 클럭설정 - HSI, HSE 480Mhz

STM32H7의 최대 클럭 속도는 480Mhz 이다. HSI, HSE 로 각각 클럭 설정이 가능하다.



STM32H7 HSI 480Mhz

칩 내부에 64Mhz RC 오실레이터가 있어 최대 480Mhz로 설정이 가능하다.

STM32CubeMx에서 아래와 같이 설정하면 내부 클럭으로 480Mhz까지 설정 가능하다.





STM32CubeMx 에서 HSI 480Mhz로 생성한 코드


STM32H7 HSI 480Mhz

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 = 60;
  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);

}





STM32H7 HSE 480Mhz @25Mhz XTAL




STM32CubeMx 에서 HSI 480Mhz로 생성한 코드

STM32H7 480Mhz HSE @25Mhz XTAL

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_SCALE0);
  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 = 60;
  RCC_OscInitStruct.PLL.PLLP = 2;
  RCC_OscInitStruct.PLL.PLLQ = 5;
  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_4) != 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);

}


Posted by nexp

댓글을 달아 주세요