아트메가/이론

ATMEGA128을 STM32코드 형식(HAL 라이브러리) 으로 바꾸기

원원 2023. 3. 1. 17:11

안녕하세요. 오늘은 ATMEGA128코드를 STM32 코드 형식(HAL 라이브러리)으로 바꿔보겠습니다.
먼저 "아트메가/이론 ATMEGA128 주솟값으로 제어하기" 글 참고바랍니다. https://wowon.tistory.com/280

GPIO A,B,C출력/입력만 테스트 해보겠습니다.

 

먼저 제어할 레지스터가 PORT, DDR, PIN입니다. 데이터들은 1바이트씩이고 PIN다음에 DDR이 나오고 다음에 PORT가 나옵니다.
먼저 GPIO 주소의 시작점을 define해줍니다.

#define GPIOA_BASE (0x39)
#define GPIOB_BASE (0x36)
#define GPIOC_BASE (0x33)

 

그리고나서 PIN,DDR,PORT 구조체를 만듭니다

typedef struct
{
	volatile unsinged char PIN;
	volatile unsinged char DDR;
	volatile unsinged char PORT;
} GPIO_TypeDef;

이 구조체에서 PIN의 주소가 0x00이면 DDR은 0x01이고 PORT는 0x02입니다. 데이터시트에서 레지스터들의 간격이 1바이트라서 이런식으로 선언한거고 만약 PIN이 0x00이고 DDR의 주소가 0x0A라면 구조체에서 주소값 0x01~0x09 크기의 배열을 선언해줘야 합니다.

 

이제 사용할 GPIO를 선언합니다. (GPIO_TypeDef * )로 타입전환을 해버리면 데이터시트처럼 사용이 가능합니다.

#define GPIOA   ((GPIO_TypeDef*) GPIOA_BASE)
#define GPIOB   ((GPIO_TypeDef*) GPIOB_BASE)
#define GPIOC   ((GPIO_TypeDef*) GPIOC_BASE)

예를들어서 위에서 선언했듯이 GPIOA_BASE는 0x39입니다. 0x39는 PINA입니다. 0x39에다가 (GPIO_TypeDef *) 포인터형 선언을 한다면 0x39는 PIN이고 0x40은 DDR이고 0x41은 PORT가 됩니다.

 

위에까지가 STM32 HAL 라이브러리에서 레지스터를 정의하는 방식입니다. 이제 이 방식을 사용하여 코드를 작성해보겠습니다.

#define F_CPU 16000000UL
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <string.h>

#define __IO                       volatile
#define GPIO_PIN_0                 ((uint8_t)0x01)  /* Pin 0 selected    */
#define GPIO_PIN_1                 ((uint8_t)0x02)  /* Pin 1 selected    */
#define GPIO_PIN_2                 ((uint8_t)0x04)  /* Pin 2 selected    */
#define GPIO_PIN_3                 ((uint8_t)0x08)  /* Pin 3 selected    */
#define GPIO_PIN_4                 ((uint8_t)0x10)  /* Pin 4 selected    */
#define GPIO_PIN_5                 ((uint8_t)0x20)  /* Pin 5 selected    */
#define GPIO_PIN_6                 ((uint8_t)0x40)  /* Pin 6 selected    */
#define GPIO_PIN_7                 ((uint8_t)0x80)  /* Pin 7 selected    */

#define GPIOA_BASE (0x39)
#define GPIOB_BASE (0x36)
#define GPIOC_BASE (0x33)

#define GPIO_OUTPUT   1
#define GPIO_INPUT    0

#define GPIO_NOPULL   0
#define GPIO_PULLUP   1
#define GPIO_PULLDOWN 2

typedef struct
{
	__IO uint8_t PIN;
	__IO uint8_t DDR;
	__IO uint8_t PORT;
} GPIO_TypeDef;

typedef struct
{
	uint8_t Pin;
	uint8_t Mode;
	uint8_t Pull;
} GPIO_InitTypeDef;


#define GPIOA   ((GPIO_TypeDef*) GPIOA_BASE)
#define GPIOB   ((GPIO_TypeDef*) GPIOB_BASE)
#define GPIOC   ((GPIO_TypeDef*) GPIOC_BASE)


void HAL_GPIO_Write(GPIO_TypeDef* GPIOx, uint8_t GPIO_Pin, uint8_t PinState);
void HAL_GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef *GPIO_Init);
uint8_t HAL_GPIO_ReadPin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin);
void MX_GPIO_Init(void);

int main(void)
{
	MX_GPIO_Init();
	HAL_GPIO_Write(GPIOA, GPIO_PIN_0, 1);
	while(1)
	{
		if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_1))
			HAL_GPIO_Write(GPIOA,GPIO_PIN_0,1);
		else
			HAL_GPIO_Write(GPIOA,GPIO_PIN_0,0);
	}
}

void HAL_GPIO_Write(GPIO_TypeDef* GPIOx, uint8_t GPIO_Pin, uint8_t PinState)
{
	if(PinState != 0) 
		GPIOx->PORT |= GPIO_Pin;
	else
		GPIOx->PORT &= ~GPIO_Pin;
}

void HAL_GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef *GPIO_Init)
{
	uint32_t position = 0x00;
	uint32_t ioposition;
	uint32_t iocurrent;
	while (((GPIO_Init->Pin) >> position) != 0x00)
	{
		ioposition = (0x01uL << position);
		iocurrent = (uint32_t)(GPIO_Init->Pin) & ioposition;
		if (iocurrent == ioposition)
		{
			switch (GPIO_Init->Mode)
			{
				case GPIO_OUTPUT:
					GPIOx->DDR |= ioposition;
					break;
				case GPIO_INPUT:
					GPIOx->DDR &= ioposition;
					if(GPIO_Init->Pull == GPIO_PULLUP)
						GPIOx->PORT |= ioposition;
					break;
			}
		}
		position++;
	}
}

uint8_t HAL_GPIO_ReadPin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin)
{
	uint8_t bitstatus;
	if ((GPIOx->PIN & GPIO_Pin) != 0)
	{
		bitstatus = 1;
	}
	else
	{
		bitstatus = 0;
	}
	return bitstatus;
}

void MX_GPIO_Init(void)
{
	GPIO_InitTypeDef GPIO_InitStruct = {0};

	/* GPIOA, PIN0, OUTPUT */
	GPIO_InitStruct.Pin = GPIO_PIN_0;
	GPIO_InitStruct.Mode = GPIO_OUTPUT;
	GPIO_InitStruct.Pull = GPIO_NOPULL;
	HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
	
	/* GPIOB, PIN1, INPUT, PULLUP */
	GPIO_InitStruct.Pin = GPIO_PIN_1;
	GPIO_InitStruct.Mode = GPIO_INPUT;
	GPIO_InitStruct.Pull = GPIO_PULLUP;
	HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
}

ATMEGA랑 STM32랑 레지스터초기화하는 방식이 조금 달라서 ATMEGA에 맞게 수정했고 최대한 비슷하게 하려고 했습니다.
프로그램은 B포트 1번핀이 LOW면 A포트의 0번이 LOW이고 B포트 1번핀이 HIGH면 A포트의 1번핀이 HIGH입니다

프로그램을 넣었을때 값입니다. B포트 1번핀이 풀업설정이므로 A포트 1번이 HIGH입니다.

 

B포트1번핀에 LOW를 넣은 모습입니다. A포트 1번이 LOW가 됐습니다.