크리스, 나는, 코어 텍스 M 전문가가 아니다. 그러나 위의 설명을 기반으로 주변 장치 레지스터의 단일 비트를 수정하는 데 상당히 복잡한 방법을 사용하려고합니다. 정상적으로 처리하는 데는 두 가지 방법이 있습니다.
매크로 집합 (가장 익숙한 매크로)을 사용하십시오. 이렇게하면 매크로가 컴파일 시간 동안 필요한 정확한 값/연산으로 직접 변환되기 때문에 핀의 각 읽기/쓰기에 대한 공간 및 CPU 시간과 호출 함수 오버 헤드가 줄어 듭니다.
대신 PF4 레지스터의 비트 밴드 주소를 사용하십시오 (Cortex-M을 사용하지 않았습니다). 이것은 당신의 아키텍쳐에서 선호하는 방법처럼 보입니다.
ARM Cortex-M4 기술 참조 설명서 3.4 절에 따라 비트 밴드 별칭 주소를 사용하여 PF4 비트를 수정할 수 있습니다. TRM 섹션 3.7에서 그 작동 방식에 대한 세부 정보를 찾을 수 있습니다.
주소 0x40025040에서 PF4의 위의 코드 인 비트 4를 기반으로, 비트 밴드의 공식은 (공정 사용에 따라 TRM에서 촬영) 제공합니다 bit_band_base
•
별칭 영역의 시작 주소입니다. (0x42000000) byte_offset
은 대상 비트가 들어있는 비트 밴드 영역의 바이트 수입니다. (0x00025040) • bit_number
은 대상 비트의 비트 위치 (0 ~ 7)입니다. (0x4로) bit_word_offset
•
bit_word_offset = (byte_offset x 32) + (bit_number × 4)
bwo = 0x25040* 0x20 + 0x4 * 0x4 = 0x004A0810
bit_word_addr = bit_band_base + bit_word_offset
bwa = 0x42000000 + 0x4A0810 = 0x424A0810
는 비트 밴드 메모리 영역의 목표 비트의 위치이다. bit_word_addr
은 대상 비트에 매핑되는 별칭 메모리 영역의 단어 주소입니다.
그래서
*(volatile unsigned long *)0x424A0810 = 0x1;
당신이 정말 기능과 직접 쓰기를 사용하는 경로를 이동하려면
*MyOutput |= 0x10;
를 작성 동일, 대신 단지 PF31을 (제한이 시도 PF 경우 독자보다는 독자적으로 구현 된 31 개 이상 필요). 이 코드에는 PC 기반 테스트 #define
이 포함되어 있으므로 명령 줄에서 gcc로 컴파일 할 수 있습니다.
#include <inttypes.h>
#include <stdio.h>
#define PC_TESTING 1
#if PC_TESTING
unsigned long FAKE_PFBASE;
#define PFBASE &FAKE_PFBASE
#else
#define PFBASE (volatile unsigned long *) 0x40025040
#endif
#define SUCCESS 0
#define ERROR_INVALID_PIN -1
#define ERROR_INVALID_STATE -2
typedef enum {OFF = 0, ON} ONOFF_t;
typedef enum { PF0 = 0, PF1, PF2, PF3, PF4, PF5, PF6, PF7, PF8, PF9, PF10, PF11, PF12, PF13, PF14, PF15, PF16, PF17, PF18, PF19, PF20, PF21, PF22, PF23, PF24, PF25, PF26, PF27, PF28, PF29, PF30, PF31 } PIN_t;
int SetOutput(PIN_t PIN, ONOFF_t ONOFF)
{
uint32_t mask, value;
// Implementing more than 32 pins is exercise for the reader
if (PIN > 31)
return ERROR_INVALID_PIN;
// In case someone did something wrong
if (ONOFF != OFF && ONOFF != ON)
return ERROR_INVALID_STATE;
//Broken into separate steps for ease of reading
//Select the bit of interest
mask = 1 << PIN;
//Clear the bit of interest
value = *PFBASE & ~mask; //~ is a bit-wise invert. 0x0000 0010 becomes 0xFFFF FFEF
//Set the bit of interest if that is requested
if(ON == ONOFF)
value |= mask;
*PFBASE = value;
return SUCCESS;
}
int main()
{
int success = 0;
FAKE_PFBASE = 0l;
success = SetOutput(PF4, ON);
printf (" Success = %d, *PFBASE = 0x%08x\n", success, *PFBASE);
success = SetOutput(PF0, ON);
printf (" Success = %d, *PFBASE = 0x%08x\n", success, *PFBASE);
success = SetOutput(PF0, OFF);
printf (" Success = %d, *PFBASE = 0x%08x\n", success, *PFBASE);
//Error handling left to reader
success = SetOutput(33, OFF);
printf (" Success = %d, *PFBASE = 0x%08x\n", success, *PFBASE);
success = SetOutput(PF2, 2);
printf (" Success = %d, *PFBASE = 0x%08x\n", success, *PFBASE);
return 0;
}
샘플 출력 :
$ ./a.out
Success = 0, *PFBASE = 0x00000010
Success = 0, *PFBASE = 0x00000011
Success = 0, *PFBASE = 0x00000010
Success = -1, *PFBASE = 0x00000010
Success = -2, *PFBASE = 0x00000010
당신이 우리에게'PF4' 또는 주소 * 0x40025040 *에 대한 자세한 내용을 알 수 있습니까? SOC/CPU가 무엇입니까? 모든 GPIO 메모리 컨트롤러가 동일하지는 않습니다. –
그것은 ARM Cortex M4입니다. 주소 0x40025040은 포트 F Pin4의 기본 포트입니다. 개별 비트 주소 지정을 허용하지만 여전히 비트 값으로 설정해야합니다 (예 : MyOutput = 0x10, PF4의 경우 1). 각 IO의 SETvalue에 대해 많은 상수를 작성하는 대신 핀의 주소를 기반으로 핀 비트 마스크를 작성하는 함수를 작성하고 싶습니다. 원하는 주소와 값을 전달하면 해당 핀의 올바른 비트 마스크가 반환됩니다. 나는 논리가 정확하다고 생각하지만 그것은 int 주소를 변환하는 데 문제가있는 것 같습니다. 바이너리 표현식 ('long *'및 'int ')에 대한 잘못된 피연산자 가져 오기 – chrismec
포인터를 int로 캐스트하여 마스크 할 수 있습니다. 예를 들어,'bit = ((uint32) PIN & 0x1f0UL) >> 4;'그리고 나서'mask = 1 << bit;'를 사용하십시오. 포트가 0x40025000, 0x40025010, 0x40025020, 0x40025030, 0x40025040 ...이라고 추측합니다. 따라서 두 번째로 낮은 니블을 선택하고 비트 시프트로 사용하십시오. 일반적으로 핀 간격은 고정되어 있으며 16 바이트라고 가정합니다. –