STM32 MCU 는 PSOC5과 같이 포트를 맘대로 바꾸기 어려워서,

이런 저런 기능을 사용하고 나면 못쓰는 기능들이 생깁니다.

저의 경우에는, TIMx PWM_CHx 핀을 쓰고 싶은데, 없고 TIMx PWM_CHxN 핀은 있어서,
뭐가 다른가 하고 테스트를 해보게 되었습니다.
물론, 메뉴얼을 좀 읽어 보니까 Complementary outputs 기능을 사용할 경우에는 의미가 있지만, 그 내용은 일단 생략하고,
단순한 PWM 출력만을 놓고 테스트 해 봤을 때는, 이름만 다르지 전혀 차이가 없이 사용 가능했습니다.

이 테스트는 STM32F411 Nucleo 보드에서 진행 하였고, 다음과 같은 포트를 사용했습니다.








TIM2 의 설정은 PWM 출력 1개가 나오는데, 이건 오실로 스코프로 찍기 쉽게 
펄스 하나를 TIM2 Update 인터럽트에 맞춰서 내보내도록 설정 한 것으로 중요한 내용이 아니라서 통과하고,
TIM1 의 PWM_CH1 과 PWM_CH2N 을 완벽하게 같은 조건으로 설정하고 포트 출력을 확인해 봤습니다.

[TIM1 PWN 채널 출력 설정]





[위의 설정에 따른 결과]





[설명]
위의 설정은 TIM2 Update INT 마다 TIM1 의 PWM_CH1 과 PWM_CH2N 을 완전히 똑같은 조건으로,
(One Pulse Mode, 5-repeat , 주기 : 5ms, Duty : 1/10) 출력하도록 프로그램을 했고,
오실로 스코프로 출력을 측정한 사진입니다.

결론은 일반적인 PWM 신호를 포트로 출력할 경우는, PWM_CHx 나 PWM_CHxN 은 동일한 출력을 내므로,
PWM_CHx 가 없고 PWM_CHxN 만 있다면 그것을 써도 무방하다.

다만, 프로그램에서 출력 함수가 다르다.
PWM_CHx 출력 함수는 HAL_TIM_OC_Start(TIM_HandleTypeDef *htim, uint32_t Channel)인데,
PWM_CHxN 출력 함수는 HAL_TIMEx_OCN_Start(TIM_HandleTypeDef *htim, uint32_t Channel) 입니다.

다음은 CUBEMX 툴로 설정된 내용을 KEIL 코드로 변환한 소스 중에서,
제가 임의로 추가한 부분입니다.
다음은 먼저 main.c 파일의 main() 함수에서 TIM2 Update Interrupt 시작하는 코드와 TIM2 PWM 포트 출력 코드 이고,
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
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();
 
  /* Configure the system clock */
  SystemClock_Config();
 
  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_TIM1_Init();
  MX_TIM2_Init();
 
  /* USER CODE BEGIN 2 */
  HAL_Delay(500);
  HAL_TIM_Base_Start_IT(&htim2);
    HAL_TIM_OC_Start(&htim2,TIM_CHANNEL_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 */
 
}
cs

이 TIM2 인터럽트에 의해 TIM1_PWM_CH1 과 TIM2_PWM_CH2N 을 출력하는 코드입니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
  /* Prevent unused argument(s) compilation warning */
    if (htim->Instance == TIM2)
    {
        HAL_TIMEx_OCN_Start(&htim1,TIM_CHANNEL_1);
        HAL_TIM_OC_Start(&htim1,TIM_CHANNEL_2);
    }
    else if (htim->Instance == TIM1)
    {
    }
  /* NOTE : This function Should not be modified, when the callback is needed,
            the __HAL_TIM_PeriodElapsedCallback could be implemented in the user file
   */
}
cs


전체 프로젝트를 첨부해 둡니다.

pwm_chN_out.zip



이전에 올린 글 "[STM32F4xx] uSD-Card USB MSC(Mass Storage Class) CUBEMX 설정 (1/2)" 에 이어서,

프로그램 수정 사항을 올립니다.

MSC 의 수정할 부분은 의외로 별로 없습니다.
CUBEMX 에서 설정만 잘 했으면, usbd_storage_if.c 파일만 손보면 됩니다.

1. #include 추가.
1
2
3
4
5
6
/* Includes ------------------------------------------------------------------*/
#include "usbd_storage_if.h"
/* USER CODE BEGIN INCLUDE */
#include "bsp_driver_sd.h"
/* USER CODE END INCLUDE */
 
cs


2. STORAGE_Init_FS() 함수 수정.
1
2
3
4
5
6
7
int8_t STORAGE_Init_FS (uint8_t lun)
{
  /* USER CODE BEGIN 2 */ 
    BSP_SD_Init();
    return (USBD_OK);
  /* USER CODE END 2 */ 
}
cs


3. STORAGE_GetCapacity_FS() 함수 수정.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
int8_t STORAGE_GetCapacity_FS (uint8_t lun, uint32_t *block_num, uint16_t *block_size)
{
  /* USER CODE BEGIN 3 */   
  HAL_SD_CardInfoTypedef info;
 
    BSP_SD_GetCardInfo(&info);
 
    *block_num = (info.CardCapacity)/STORAGE_BLK_SIZ  - 1;
    *block_size = STORAGE_BLK_SIZ;
//  *block_num  = STORAGE_BLK_NBR;
//  *block_size = STORAGE_BLK_SIZ;
  return (USBD_OK);
  /* USER CODE END 3 */ 
}
cs

4. STORAGE_Read_FS() 함수 수정.
1
2
3
4
5
6
7
8
9
10
int8_t STORAGE_Read_FS (uint8_t lun, 
                        uint8_t *buf, 
                        uint32_t blk_addr,                       
                        uint16_t blk_len)
{
  /* USER CODE BEGIN 6 */ 
    BSP_SD_ReadBlocks_DMA((uint32_t *)buf, blk_addr * STORAGE_BLK_SIZ,STORAGE_BLK_SIZ, blk_len);
  return (USBD_OK);
  /* USER CODE END 6 */ 
}
cs

5. STORAGE_Write_FS() 함수 수정.
1
2
3
4
5
6
7
8
9
10
int8_t STORAGE_Write_FS (uint8_t lun, 
                         uint8_t *buf, 
                         uint32_t blk_addr,
                         uint16_t blk_len)
{
  /* USER CODE BEGIN 7 */ 
    BSP_SD_WriteBlocks_DMA((uint32_t *)buf, blk_addr * STORAGE_BLK_SIZ,STORAGE_BLK_SIZ, blk_len);
  return (USBD_OK);
  /* USER CODE END 7 */ 
}
cs

이상이고, SDIO_CD (Card Detection) 신호를 사용하려면 위 함수들에 약간의 추가적인 코드가 필요합니다.
이전 글의 마지막에 링크된 웹사이트를 참고하셔서 수정하시면 됩니다.

다음은, 이 USB MSC 로 생성된 USB 드라이브 내용입니다.




엊그제 uSDcard 내용을 읽어서 USB CDC 로 터미널에 뿌렸던 내용과는 너무나 깔끔하고 좋네요.
파일을 PC에서 수정 가능하고, 쉽게 읽고 쓸 수 있습니다. ^^

[엊그제 uSDcard 내용을 읽어서 USB CDC 로 터미널에 뿌렸던 내용




요새 uSD-Card를 보드에 직접 납땜을 해서,

파일을 수정할 방법을 강구하다가 USB MSC(Mass Storage Device Class)를 공부하게 됐습니다.
2일 동안 회사에서 의자에 붙어서 열심히 팠습니다. ㅠㅠ

된다고 하는 여러 예제들이 있었는데, 왜 나만 안되는 것인지.. 참 답답했는데,
원인은 여러가지겠지만, 
가장 큰 원인은 인터럽트 우선순위를 설정하지 않고 모두 0으로 놓으니 동작이 안됐던 것 같았습니다.

그럼, 차근차근 설명을 해 보겠습니다.
제가 테스트하는 H/W 는 
1. SD-Card SDIO-4Bit DMA , 
2. USB Device Only , 
3. Embedded DFU 방식으로 F/W Upload. (BOOT0 핀과 GPIO INPUT 핀에 공통으로 스위치 사용)
4. BOOT1 을 GPIO OUT(LED OUT) 과 공통으로 사용.
5. RCC(HSE)로 24MHz Crystal 사용.
6. Middle Wares -> FATFS -> SD Card 설정.
7. SDPWR 은 필요 없는 기능이니 신경쓰지 마시고요.
으로 어제와 동일합니다.




어제 쓴 글에서는 디렉토리만 읽어서 USB CDC로 표시만 할 수 있었는데, 이번에는 MSC로 읽기 쓰기를 구현해 보고자,
CUBEMX 툴에서 USB_DEVICE 타입을 Mass Storage Class 로만 변경했습니다.






클락 탭의 설정은 다음과 같습니다.






다음은 CUBEMX 의 Configuration TAB의 상세 설정입니다. 
바꾼 것들만 설명을 할 것인데, 그 외의 설정은 디폴드 설정으로 건드리지 않았습니다.
NVIC 는 각각의 상세 설정에도 있고, 따로 NVIC 설정이 분리되어 있는데, 맨 마지막에 NVIC를 수정할 예정입니다.

















다음은 NIVC(인터럽트 우선순위) 설정으로 어떻게 정하는지 저도 잘 모르겠습니다만, MSC 안 되었던 이유 중 가장 큰 원인이, 이 우선순위를 수정하지 않고 모두 우선순위가 0(Default)으로 내버려 뒀기 때문이었습니다.
나중에 같은 실수를 방지하기 위해, 어떤 기준으로 정하는 것인지 확실히 정리해야 할 것 같습니다.






다음으로 HEAP 과 STACK 을 충분히 잡아 두라해서 일단은 최적화는 못했고, 무식하게 크게 잡아두었습니다.





글이 생각보다 너무 길어지고 시간이 너무 늦어서, S/W 쪽은 눈을 좀 붙이고 시간이 나면 작성하도록 하겠습니다.
제가 여러가지를 참고해서 S/W를 만들었는데, 일단 참고한 윕사이트를 링크해 드립니다.



+ Recent posts