STM32CubeIDE에서 ST-LINK로 펌웨어를 다운로딩 할 때 주로 Debug나 Run버튼을 사용하여 다운로딩 할겁니다.

 

그러던 도중 발생한 에러!

에러 메세지 창

 

콘솔 메세지 창

 

프로그램 다운이 실패했다는건 대충 알겠는데 에러 메세지가 DEV_TARGET_NOT_HALTED 를 나타냅니다.

 

이 에러는 플래시가 Erase나 Write 등의 동작 중에 플래시 다운을 시도할 때 발생합니다.

프로그램 시작 부분에 플래시 Erase 코드가 있으면 이런 에러 메세지가 나타날 수 있습니다.

이것을 해결하기 위해서는

 

Run -> Run Configurations -> Debugger -> Reset behaviour Type을 None으로 설정 -> Apply 입니다.

 

Run Configurations 위치

 

Reset behaviour 설정 위치

 

 

출처: ST-LINK error (DEV_TARGET_NOT_HALTED)

반응형

사용 MCU : STM32F103VCT

 

Uart를 사용하기 위해서 CubeMX에서 USART1을 아래와 같이 활성화 시킵니다.

 

통신속도는 115200 Bits/s로 설정합니다. 

 

아래와 같이 USART TX RX 핀이 활성화 됩니다.

 

 

인터럽트 설정을 하기 위해서 NVIC에서 USART1 global interrupt Enabled에 체크합니다.

 

 

 

 

UART 관련 함수

// Uart 송신 인터럽트 함수: Uart Tx로 데이터를 Size만큼 전송하면 인터럽트가 발생한다.
// huart: uart 인스턴스
// pData: 송신 데이터 버퍼
// Size: 송신 데이터 개수
HAL_StatusTypeDef HAL_UART_Transmit_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);


// Uart 수신 인터럽트 함수: Uart Rx로 데이터가 Size만큼 들어오면 인터럽트가 발생한다.
// huart: uart 인스턴스
// pData: 수신 데이터 버퍼
// Size: 수신 데이터 개수
HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);

 

UART Interrupt예제

/*
  Uart Interrupt Echo 예제
  
  인터럽트로 수신한 Uart 데이터를 전송한다.
  
  main.c
*/


uint8_t rx_data;


// 인터럽트 콜백 함수: 인터럽트가 발생되면 이 함수가 호출된다.
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) {
	if (huart->Instance == USART1) {
        // 데이터 1개를 수신하면 인터럽트를 발생시킨다.
		HAL_UART_Receive_IT(&huart1, &rx_data, 1);
        
        // 받은 데이터를 전송한다.
		HAL_UART_Transmit(&huart1, &rx_data, 1, 10);
	}
}



void main ()
{

  /* 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_USART1_UART_Init();

  /* Initialize interrupts */
  MX_NVIC_Init();
  /* USER CODE BEGIN 2 */
  HAL_UART_Receive_IT(&huart1, &rx_data, 1);
 /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

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

 

예제에서는 간단하게 인터럽트 수신을 받으면 바로 송신하도록 하였지만,

 

실제 운용할 때에는 Queue Buffer를 구성하고 main 에서 데이터를 빼내어 사용하여야 합니다.

 

[MCU/STM32:HAL] - [HAL][STM32F]USART와 Queue

반응형

DAC는 ADC의 반대로, Digital값을 Analog 값으로 변환하는 모듈입니다.

 

STM32F103에는 12bit DAC 모듈을 가지고 있습니다.

0부터 Vref+ 에 인가된 전압을 4096(2^12)개로 쪼개어 출력으로 보냅니다.

 

DAC 출력 공식(출처: Reference Manual)

DACoutput:  DAC 출력

VREF: VREF+ 핀에 인가된 전압

DOR: Data Output Register로 여기에 0~4095값이 쓰여짐

 

 

Vref+ 가 3.3V일경우

3.3*1 / 4095 = 0.000806 이 됩니다.

 

즉 Digital Value 1당 0.000806V가 출력으로 나가게 됩니다.

 

 

CubeMX 설정

CubeMX에서 DAC 설정화면

 

여기서 Output Buffer는 DAC 출력핀의 버퍼를 두어 출력 임피던스를 줄이는 역할을 합니다.

 

* DAC Output Buffer를 Enable로 했을 경우, 200mV 이하로 내려가지 않는 이슈가 있습니다.

community.st.com/s/question/0D50X00009XkXzE/minimum-dac-output-voltage-on-stm32f30x

 

PA4와 PA5핀에 DAC 기능이 활성화된 화면

 

HAL

HAL 드라이버에서 초기화를 제외한 DAC에 필요한 함수는 아래와 같습니다.

HAL_StatusTypeDef HAL_DAC_Start(DAC_HandleTypeDef *hdac, uint32_t Channel);
// DAC Output Enable 함수
// hdac: dac 인스턴스
// Channel: DAC_CHANNEL_1 or DAC_CHANNEL_2

HAL_StatusTypeDef HAL_DAC_Stop(DAC_HandleTypeDef *hdac, uint32_t Channel);
// DAC Output Disable 함수
// hadc: dac 인스턴스
// Channel: DAC_CHANNEL_1 or DAC_CHANNEL_2

HAL_StatusTypeDef HAL_DAC_SetValue(DAC_HandleTypeDef *hdac, uint32_t Channel, uint32_t Alignment, uint32_t Data);
// DAC Value 설정 함수
// hadc: dac 인스턴스
// Channel: DAC_CHANNEL_1 or DAC_CHANNEL_2
// Alignment: DAC_ALIGN_12B_R or DAC_ALIGN_12B_L or DAC_ALIGN_8B_R
// data: 0 ~ 4095 값

 

Alignment 설정에 따라 데이터가 정렬되는 모습

 

사용법

 

목표: DAC 채널 1의 출력을 2V로 설정하고 싶다.

 

DOR = 2V * 4095 / 3.3V = 2481.82 ≒ 2482 

 

HAL_DAC_SetValue(&hdac1, DAC_CHANNEL_1, DAC_ALIGN_12B_R, 2482);

HAL_DAC_Start(&hdac1, DAC_CHANNEL_1);

 

반응형

실시간으로 데이터를 수집하여 DataGridView에 데이터를 나타내기 위해 데이터를 추가할 때 점점 갈 수록

속도가 오래걸리는 현상을 발견했습니다. (1400개 이상 데이터)

 

Column 수가 많아 DataGridView의 영역이 벗어날 때 

데이터를 추가할 때마다 DataGridView를 벗어난 영역이 깜빡이는 것을 확인 할 수 있었습니다.

이 때문에 점점 느려진다고 판단하였습니다.

 

 

이를 해결하기 위해서는 DataGridView에 더블버퍼를 설정해야합니다.

 

설정하는 방법은 아래 포스팅을 참조해주세요.

[C#] - [C#, DataGridView] 데이터 추가시 DataGridView 깜빡임 문제 해결

 

더블버퍼를 설정하면 데이터 양이 많아질 수록 속도가 안 느려지는 것은 아니지만, 

훨씬 개선된 것을 느낄 수 있습니다.

 

 

출처: https://stackoverflow.com/questions/10226992/slow-performance-in-populating-datagridview-with-large-data

반응형

DataGridView에 source를 등록 후 

새로운 row나 값을 추가 할 때 DataGridView가 깜빡이는 현상을 볼 수 있습니다.

 

이것을 해결하기 위해서 더블버퍼를 설정 해 주어야 합니다.

 

 


   

using System.Reflection;


public partial class Form1 : Form
{
   ...
   
   
  ...


  private void Init_DataGridView()
  {
    dataGridView1.DoubleBuffered(true);
  }
}

public static class ExtensionMethods 
{ 
  public static void DoubleBuffered(this DataGridView dgv, bool setting) 
  { 
    Type dgvType = dgv.GetType(); 
    PropertyInfo pi = dgvType.GetProperty("DoubleBuffered", BindingFlags.Instance | BindingFlags.NonPublic); 
    pi.SetValue(dgv, setting, null); 
  } 
}

 

 

출처: https://stackoverflow.com/questions/41893708/how-to-prevent-datagridview-from-flickering-when-scrolling-horizontally

반응형

TrueStudio로 프로젝트를 진행하다가

디버그 버튼을 눌러 다운로딩 할 때 프로젝트에 에러가 있으면 아래와 같은 메세지 창이 뜹니다.

 

저 메시지가 너무 귀찮았던 나머지 "항상 확인 없이 실행" 에 체크 후 진행 버튼을 눌렀었죠..

 

그 다음부터는 에러가 발생해도 저 메시지를 보여주지 않고 펌웨어 다운로드를 하더라고요

 

아 이건 아니지 싶어 다시 원상복구를 시키려고 찾아보니 

창-> 환경설정 -> 실행/디버그 -> 실행 -> 프로젝트에 오류가 있어도 계속 실행에 "항상"에 체크되어있더라고요

 

이것을 "프롬프트"로 바꿔주고 확인버튼을 누르면 다시 위의 메시지를 볼 수 있습니다.

 

반응형

사용 MCU: STM32F103RETx

컴파일러: Truestudio 9.3.0

 

 

목표: Timer8의 4번 채널을 사용해서 3KHz의 클럭을 생성

 

 

저는 Output Compare기능을 클럭 신호와 같이 일정 시간마다 출력을 토글시켜주어야 할 때 사용합니다.

 

아래는 클럭 설정입니다. 최대 클럭 72MHz로 설정합니다.

MCU 클럭 설정

 

타이머를 설정합니다.

 

CubeMX에 Timers 카테고리에 TIM8을 선택 해 줍니다.

 

 

 

Clock Source를 Internal Clock으로 설정해서 내부 클럭에 의해 타이머가 카운트 되도록 설정하고

채널 4번에 클럭을 생성한다고 했으니 Channel4에 Output Compare CH4를 선택해줍니다.

그러면 다음과 같이 MCU 핀에 TMI8_CH4 라벨이 붙었습니다.

 

 

Output Compare Channel 4의 Mode를 Toggle on match를 선택하여 OC가 될 때 GPIO가 토글되도록 합니다.

 

Timer 주기를 선택해 줍니다.

3KHz의 주파수를 만들기 위해서 

 

72MHz / 1000 / 24 = 3000 가 나옵니다. 즉 숫자를 3000번 세면 Output Compare 인터럽트가 발생하여 토글 시키는데 그러면 GPIO 출력으로 나오는 클럭이 1500Hz가 되기 때문에  2를 더 나누어서 설정합니다

 

72MHz / 1000 / 24 / 2 = 1500 라서 

 

Prescaler 에 12 - 1,

Counter Period에 1000 - 1을 넣습니다

 

 

 

코드는 while에 들어가기전에 HAL_TIM_OC_Start(타이머 번호, 채널 번호) 값을 넣어 호출해주면 PC9번 핀에 클럭이 나오는 것을 볼 수 있습니다.

int main()
{
 ...
 MX_TIM8_Init();

 ...
 
 // Timer8 Output Compare 시작
 HAL_TIM_OC_Start(&htim8, TIM_CHANNEL_4);
 
 
 while(1)
 {
 
 
 }
}
반응형

'MCU > STM32:HAL' 카테고리의 다른 글

[STM32F]FSMC와 LCD  (0) 2021.02.28
[STM32F]FSMC로 LCD(SSD1963) 제어하기  (2) 2021.02.07
[STM32F][HAL] USART Interrupt  (0) 2020.12.23
[STM32F][HAL] DAC (Digital to Analog Converter)  (0) 2020.12.22
[STM32F][HAL] USB CDC (Virtual Port Com) 사용하기  (1) 2020.05.28
[STM32F][HAL] HAL_Delay  (0) 2020.05.21
[STM32F][HAL] ADC - ADC Calibration  (4) 2020.05.17
[STM32F][HAL]GPIO  (0) 2020.05.10

사용 MCU: STM32F103VCT

 

안녕하세요.

 

STM32F103에 있는 USB IP중 CDC(Communication Device Class)를 CubeMX로 적용하는 방법에 대해 알아봅시다.

CDC를 사용하면 Uart 핀에 Uart To Serial 모듈을 따로 쓰지 않고 바로 USB를 통해 컴퓨터와 통신 할 수 있다는 장점이 있습니다.

 

 

제가 가지고 있는 보드의 USB 회로는 아래와 같습니다.

USB 회로

컴퓨터에서 USB를 인식하려면 PA1 핀이 High 상태로 있어야 합니다.

 

USB in a NutShell - Chapter 2 - Hardware (beyondlogic.org)

 

USB in a NutShell - Chapter 2 - Hardware

Connectors All devices have an upstream connection to the host and all hosts have a downstream connection to the device. Upstream and downstream connectors are not mechanically interchangeable, thus eliminating illegal loopback connections at hubs such as

www.beyondlogic.org

 

PA11과 PA12에 연결된 저항은 22옴이 사용되었습니다.

 

 

CubeMX를 실행 시켜

 

Connectivity > USB 메뉴에 Device(FS)를 체크해줍니다.

USB 기능 ON

 

 

그러면 아래 처럼 USB_DP 핀과 USB_DM핀이 활성화 될 것입니다.

 

USB 핀이 설정된 화면

 

Middleware > USB_DEVICE 메뉴로 가서 Class For FS IP를 Communication Device Class (Virtual Port Com)을 선택해주고 GENERATE CODE를 해줍니다.

 

CDC기능 ON

 

Device Descriptor 탭으로 가면 아래 화면처럼 설정되어 있습니다.

 

VID는 Vendor ID의 약자로 제조사 아이디를 뜻합니다.

 

디폴트 설정으로 1155로 설정되어있는데

모든 VID는 usb.org에서 관리되어 있습니다. 

https://usb.org/sites/default/files/vendor_ids051920_0.pdf에서 확인해 보면

1155는 STMicroelectonics라는 것을 확인 할 수 있습니다.

 

VID를 위 리스트에 없는 숫자로 해도 정상적으로 동작합니다. (15768)

 

PID는 Product ID 로 제품 ID를 설정해 주는 파라미터입니다.

 

PA1핀도 Output으로 설정해주고 Generate Code를 해줍니다.

 

USB 송수신에 관련된 함수는 usbd_cdc_if.c 파일에 있습니다.

// usbd_cdc_if.c


// USB로부터 수신한 데이터가 있을경우 호출되는 함수 
static int8_t CDC_Receive_FS(uint8_t* Buf, uint32_t *Len)
{
	...
}


// USB로부터 데이터를 송신하기 위한 함수
uint8_t CDC_Transmit_FS(uint8_t* Buf, uint16_t Len)
{
	...
}

 

 

제가 가지고 있는 보드는 PA1핀을 High로 만들어줘야지 컴퓨터가 USB를 인식한다고 했습니다.

따라서 프로그램이 시작되면 PA1핀을 High로 만들어 주고 printf가 USB를 통해 출력되도록 코드를 수정해줍니다.

 

/*
  1초마다 USB로 "Hello CDC Test\r\n" 출력하기 예제

*/

// USB로 printf를 출력시키기 위한 설정 함수
int _write(int file, char *ptr, int len){
    //HAL_UART_Transmit(&huart1, (uint8_t*)ptr, len, 100);
    // USB로 ptr를 출력합니다.
    CDC_Transmit_FS(ptr, len);
    return (len);
}


int main(void)
{
  static uint32_t time = 0;
  ...
  MX_GPIO_Init();
 
  MX_USB_DEVICE_Init();
  ...
  
  // PA1 Pin High
  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_SET);

  while (1)
  {
    if (HAL_GetTick() - time > 1000) {
      time = HAL_GetTick();
      printf("Hello CDC Test\r\n"); 
    }
  
  }

}

 

프로그램 다운로드를 완료한 후 장치관리자에 보면 아래와 같이 USB 직렬 장치라고 인식이 됩니다.

USB를 인식한 화면

 

가지고 있는 시리얼 통신 프로그램으로 COM15에 연결하면 1초마다 Hello CDC Test 라는 메세지가 나타날 것입니다.

반응형

'MCU > STM32:HAL' 카테고리의 다른 글

[STM32F]FSMC와 LCD  (0) 2021.02.28
[STM32F]FSMC로 LCD(SSD1963) 제어하기  (2) 2021.02.07
[STM32F][HAL] USART Interrupt  (0) 2020.12.23
[STM32F][HAL] DAC (Digital to Analog Converter)  (0) 2020.12.22
[STM32F][HAL] OUTPUT COMPARE 사용하기  (0) 2020.06.01
[STM32F][HAL] HAL_Delay  (0) 2020.05.21
[STM32F][HAL] ADC - ADC Calibration  (4) 2020.05.17
[STM32F][HAL]GPIO  (0) 2020.05.10

+ Recent posts