[STM32] CORDIC 가속기
CORDIC 기초
COordinate Rotation DIgital Computer의 약자로,
덧셈과 시프트 연산으로만으로 빠르게 삼각함수를 구할 수 있도록 하는 알고리즘입니다.
1959년 Jack Volder에 의해 고안되었으며, 이에 Volder's algorithm라는 명칭으로 불리기도 합니다.
ST사의 MCU 중 STM32G4 시리즈, STM32U5 시리즈, STM32H5와 STM32H7의 일부 제품이 해당 가속기를 내장하고 있습니다.
ST칩 내부의 CORDIC 연산기는 BLDC 모터 제어에서 FOC 알고리즘 계산 시, 삼각함수를 도출해내기 위해 주로 사용되며, 그외에 쌍곡선함수, 루트, 자연로그 처리 가속에도 사용될 수 있습니다.
알고리즘의 기본 아이디어를 대략적으로 표현하자면 다음과 같습니다.
1. 구하고자 하는 각도를 표시하고 아래의 행위를 몇 번(n) 반복할 것인지 정한다.
2. 기준벡터 (0.61, 0) 를 원하는 각도가 있는 곳으로 90/2 Deg 회전변환한다.
3. 구하고자 하는 각도의 벡터가 (0.61, 0)를 90/2 Deg 회전변환한 벡터와 비교하였을때,
3-1, 만약 CCW 방향으로 더 위치해있다면 이동시킨 벡터를 90/4 Deg CCW를 한다.
3-2, 만약 CW 방향으로 더 위치해있다면 이동시킨 벡터를 90/4 Deg CW를 한다.
4. 회전된 기준벡터와 목표 벡터의 위치를 고려하여 90/(2^n) Deg CW 혹은 CCW 회전변환을 총 n회 반복한다.
5. 최종 n회 변환이 되었을 때, 기준벡터의 값 (x, y)을 통하여 삼각함수 값을 도출해낸다.
자세히 수학적인 풀이는 다른 글에서 풀어보기로 합니다.
일반적으로 Sin함수와 Cos은 공업수학에서 배웠듯 테일러 시리즈를 통해 구할 수 있지만,
아시다싶히 여러 곱셈과 덧셈을 활용하는 부분이 있어 비용적으로 비싼 연산일 수 밖에 없습니다.
이에 비해 위에서 보듯 CORDIC은 덧셈과 비트연산(2의 n승)을 통해 구현될 수 있어 빠른 연산이 되지만,
예상할 수 있는 것처럼 반복횟수가 정밀도를 결정하는 부분이 있어 이 점을 유의하셔야합니다.
ST에서의 CORDIC
별도의 가속기 칩을 가지고 있다는 것은 실제로 훨씬 빠르다는 의미겠죠?
위 사진을 보면 CORDIC의 경우 CPU의 클럭 수를 29을 소모하지만, 기본적인 math.h 삼각함수 연산은 400 클럭정도 소요되는 것을 확인 가능합니다. 즉, 기본 라이브러리를 사용하는 것에 비해 20배 정도 빠르다는 것을 볼 수 있겠네요.
ST MCU에서 CORDIC 가속기를 사용하기 위해서는 몇 가지 작업이 필요합니다.
우선 앞에서 언급한 것처럼 CORDIC 가속기가 지원 가능한지 확인해주셔야합니다.
테스트용으로 STM32G431RB으로 진행합니다.
<Computing> - <CORDIC>을 통해 해당 기능을 작동시킵니다.
추가로 Advanced Settings에서 CORDIC을 LL 드라이버로 설정해줍니다.
HAL드라이버에 비해 오버헤드가 적어 더 빠르게 결괏값을 받을 수 있습니다.
전체적인 예제 코드는 아래와 같습니다.
int32_t output_sin = 0;
int32_t output_cos = 0;
int32_t ANGLE_CORDIC = 0x10000000; // 입력 각도 설정. 이는 pi/8과 같다.
LL_CORDIC_Config(
CORDIC,
LL_CORDIC_FUNCTION_COSINE, // 코사인 함수 설정.
LL_CORDIC_PRECISION_6CYCLES, // 최대 정밀도 설정
LL_CORDIC_SCALE_0, // 스케일링하지 않음.
LL_CORDIC_NBWRITE_1, // 입력 데이터 : 첫번째는 각도입력, 두번째 입력은 Modulus이나, 1로 설정
LL_CORDIC_NBREAD_2, // 출력 데이터 : cosine이 먼저. 그 다음은 sine으로 설정.
LL_CORDIC_INSIZE_32BITS, // 입력데이터 형식을 q1.31로 설정
LL_CORDIC_OUTSIZE_32BITS); // 출력데이터 형식을 q1.31로 설정
LL_CORDIC_WriteData(CORDIC, ANGLE_CORDIC); // CORDIC 가속기에 각도 입력
output_cos = (int32_t)LL_CORDIC_ReadData(CORDIC); // cosine 값 읽기
output_sin = (int32_t)LL_CORDIC_ReadData(CORDIC); // sine값 읽기
하나씩 살펴봅시다.
int32_t ANGLE_CORDIC = 0x10000000; // 입력 각도 설정. 이는 pi/8과 같다.
CORDIC에 각도를 입력하기 위해서는 다음 두 가지를 유의해주셔야합니다.
우선적으로 CORDIC은 -PI ~ PI의 값이 아닌, -1 ~ 1 사이의 값을 사용합니다.
그래서 만약 PI/4값을 입력하고자 한다면 1/4으로, PI를 나눈 값을 입력해야합니다.
두번째로 Q notation이라고 불리는 고정소수점 표기 방식을 사용합니다.
CORDIC은 Q1.31과 Q1.15라는 두 가지 고정소수점 표기 방식을 사용할 수 있습니다.
Q1.31은 32비트로 고정소수점을 나타내는 방식이며, Q1.15는 16비트로 고정소수점을 나타내는 방식입니다.
위 코드는 Q1.31 표기법을 주로 설명드리자면,
위 사진같이 나타낼 수 있습니다.
코드에서 0x1000 0000라 표기했으니, 최상위 바이트에서는 0b0001 이므로, 1/8 값입니다.
따라서 이는 PI/8을 나타냅니다.
다음부분은 CORDIC 객체를 설정하는 부분입니다.
LL_CORDIC_Config(
CORDIC,
LL_CORDIC_FUNCTION_COSINE, // 코사인 함수 설정.
LL_CORDIC_PRECISION_6CYCLES, // 최대 정밀도 설정
LL_CORDIC_SCALE_0, // 스케일링하지 않음.
LL_CORDIC_NBWRITE_1, // 입력 데이터 : 첫번째는 각도입력, 두번째 입력은 Modulus이나, 1로 설정
LL_CORDIC_NBREAD_2, // 출력 데이터 : cosine이 먼저. 그 다음은 sine으로 설정.
LL_CORDIC_INSIZE_32BITS, // 입력데이터 형식을 q1.31로 설정
LL_CORDIC_OUTSIZE_32BITS); // 출력데이터 형식을 q1.31로 설정
LL_CORDIC_FUNCTION_COSINE : OUTPUT 값 2개의 순서가 COS -> SIN이 됩니다.
LL_CORDIC_PRECISION_6CYCLES : 반복횟수를 설정합니다. 사이클 횟수가 높을수록 정밀정도가 높아지며,
6사이클의 경우 최대 잔여 오차는 q1.31일 경우 2^-19정도입니다.
LL_CORDIC_SCALE_0 : CORDIC은 위에서 말한 것처럼 -1 ~ 1의 사이의 값만 사용합니다. 하지만 스케일링을 사용한다면, 이보다 큰 값을 넣을 수 있게 됩니다. 우리는 -pi ~ pi만 필요하므로 스케일링은 하지 않습니다. 스케일링을 할 시 정밀도 손상이 발생합니다.
LL_CORDIC_NBWRITE_1 : NB WRITE_1로 하게 되면, 입력값을 각도값 하나만 설정하며, Modulus는 1로 설정됩니다.
modulus는 결괏값에 곱하게되는 수를 말합니다.
LL_CORDIC_NBREAD_2 : 출력값을 2개로 설정합니다. 첫번째 출력값은 cosine이고, 두번째 출력값은 sine입니다.
NBREAD_1으로 설정하여 출력값을 1개로 하면, cosine만 나오겠죠?
LL_CORDIC_INSIZE_32BITS, LL_CORDIC_OUTSIZE_32BITS : 우리는 q1.31 즉, 32비트를 사용합니다.
이 경우 q1.15에 비해 많은 비트를 사용하지만, 정확도는 위에서 설명한 것처럼 2^-31까지 내려갑니다.
그에 비해 q1.15는 2^-15의 해상도를 가집니다.
다음 코드는 나타나는 것처럼 직관적으로 알 수 있으니 생략하도록 하겠습니다.
LL_CORDIC_WriteData(CORDIC, ANGLE_CORDIC); // CORDIC 가속기에 각도 입력
output_cos = (int32_t)LL_CORDIC_ReadData(CORDIC); // cosine 값 읽기
output_sin = (int32_t)LL_CORDIC_ReadData(CORDIC); // sine값 읽기
생각보다 쓰기 편하게 만들어진 부분이 있어, 아마 큰 무리는 없을거라 봅니다.
CORDIC에 대한 대략적인 설명과 사용은 이 정도로 하고,
다음 글에서 실제로 얼마나 빠른지 비교에 대한 글과 CORDIC의 수학적인 설명을 진행하겠습니다.
참고문헌
ST CORDIC메뉴얼
Matlab CORDIC
MATLAB의 CORDIC 알고리즘 - MATLAB & Simulink - MathWorks 한국
다음 MATLAB 명령에 해당하는 링크를 클릭했습니다. 명령을 실행하려면 MATLAB 명령 창에 입력하십시오. 웹 브라우저는 MATLAB 명령을 지원하지 않습니다.
kr.mathworks.com
ST CORDIC 교육자료
https://www.youtube.com/watch?v=g_DdzR49KiA