W tym poście chciałbym opisać sposób działania cooprocesora Cordic.
Cordic jest to cooprocesor, który wspomaga wykonywanie operacji matematycznych. Z powodzeniem może być wykorzystywany do wykonywania obliczeń na funkcjach trygonometrycznych oraz hiperbolicznych.
CubeMx:
Konfiguracja CORDIC w CubeMx jest mało skomplikowana. Należy go uruchomić:
I właściwie na tym się kończy jego konfiguracja. Dodatkowo można włączyć przerwania oraz DMA.
- static void MX_CORDIC_Init(void)
- {
- /* USER CODE BEGIN CORDIC_Init 0 */
- /* USER CODE END CORDIC_Init 0 */
- /* USER CODE BEGIN CORDIC_Init 1 */
- /* USER CODE END CORDIC_Init 1 */
- hcordic.Instance = CORDIC;
- if (HAL_CORDIC_Init(&hcordic) != HAL_OK)
- {
- Error_Handler();
- }
- /* USER CODE BEGIN CORDIC_Init 2 */
- /* USER CODE END CORDIC_Init 2 */
- }
Do tego dochodzi konfiguracja DMA:
- void HAL_CORDIC_MspInit(CORDIC_HandleTypeDef* hcordic)
- {
- if(hcordic->Instance==CORDIC)
- {
- /* USER CODE BEGIN CORDIC_MspInit 0 */
- /* USER CODE END CORDIC_MspInit 0 */
- /* Peripheral clock enable */
- __HAL_RCC_CORDIC_CLK_ENABLE();
- /* CORDIC DMA Init */
- /* CORDIC_RD Init */
- hdma_cordic_rd.Instance = DMA1_Stream2;
- hdma_cordic_rd.Init.Request = DMA_REQUEST_CORDIC_READ;
- hdma_cordic_rd.Init.Direction = DMA_PERIPH_TO_MEMORY;
- hdma_cordic_rd.Init.PeriphInc = DMA_PINC_DISABLE;
- hdma_cordic_rd.Init.MemInc = DMA_MINC_ENABLE;
- hdma_cordic_rd.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
- hdma_cordic_rd.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
- hdma_cordic_rd.Init.Mode = DMA_NORMAL;
- hdma_cordic_rd.Init.Priority = DMA_PRIORITY_LOW;
- hdma_cordic_rd.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
- if (HAL_DMA_Init(&hdma_cordic_rd) != HAL_OK)
- {
- Error_Handler();
- }
- __HAL_LINKDMA(hcordic,hdmaIn,hdma_cordic_rd);
- /* CORDIC_WR Init */
- hdma_cordic_wr.Instance = DMA1_Stream3;
- hdma_cordic_wr.Init.Request = DMA_REQUEST_CORDIC_WRITE;
- hdma_cordic_wr.Init.Direction = DMA_MEMORY_TO_PERIPH;
- hdma_cordic_wr.Init.PeriphInc = DMA_PINC_DISABLE;
- hdma_cordic_wr.Init.MemInc = DMA_MINC_ENABLE;
- hdma_cordic_wr.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
- hdma_cordic_wr.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
- hdma_cordic_wr.Init.Mode = DMA_NORMAL;
- hdma_cordic_wr.Init.Priority = DMA_PRIORITY_LOW;
- hdma_cordic_wr.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
- if (HAL_DMA_Init(&hdma_cordic_wr) != HAL_OK)
- {
- Error_Handler();
- }
- __HAL_LINKDMA(hcordic,hdmaOut,hdma_cordic_wr);
- /* USER CODE BEGIN CORDIC_MspInit 1 */
- /* USER CODE END CORDIC_MspInit 1 */
- }
- }
Powyższe konfigurację pozwalają na skonfigurowanie podstawowych peryferiów. Dalej należy skonfigurować rodzaje obsługiwanych funkcji w strukturze CORDIC_ConfigTypeDef:
- typedef struct
- {
- uint32_t Function; /*!< Function
- This parameter can be a value of @ref CORDIC_Function */
- uint32_t Scale; /*!< Scaling factor
- This parameter can be a value of @ref CORDIC_Scale */
- uint32_t InSize; /*!< Width of input data
- This parameter can be a value of @ref CORDIC_In_Size */
- uint32_t OutSize; /*!< Width of output data
- This parameter can be a value of @ref CORDIC_Out_Size */
- uint32_t NbWrite; /*!< Number of 32-bit write expected for one calculation
- This parameter can be a value of @ref CORDIC_Nb_Write */
- uint32_t NbRead; /*!< Number of 32-bit read expected after one calculation
- This parameter can be a value of @ref CORDIC_Nb_Read */
- uint32_t Precision; /*!< Number of cycles for calculation
- This parameter can be a value of @ref CORDIC_Precision_In_Cycles_Number */
- } CORDIC_ConfigTypeDef;
Pierwszym parametrem jest rodzaj obsługiwanych funkcji:
- #define CORDIC_FUNCTION_COSINE (0x00000000U) /*!< Cosine */
- #define CORDIC_FUNCTION_SINE ((uint32_t)(CORDIC_CSR_FUNC_0)) /*!< Sine */
- #define CORDIC_FUNCTION_PHASE ((uint32_t)(CORDIC_CSR_FUNC_1)) /*!< Phase */
- #define CORDIC_FUNCTION_MODULUS ((uint32_t)(CORDIC_CSR_FUNC_1 | CORDIC_CSR_FUNC_0)) /*!< Modulus */
- #define CORDIC_FUNCTION_ARCTANGENT ((uint32_t)(CORDIC_CSR_FUNC_2)) /*!< Arctangent */
- #define CORDIC_FUNCTION_HCOSINE ((uint32_t)(CORDIC_CSR_FUNC_2 | CORDIC_CSR_FUNC_0)) /*!< Hyperbolic Cosine */
- #define CORDIC_FUNCTION_HSINE ((uint32_t)(CORDIC_CSR_FUNC_2 | CORDIC_CSR_FUNC_1)) /*!< Hyperbolic Sine */
- #define CORDIC_FUNCTION_HARCTANGENT ((uint32_t)(CORDIC_CSR_FUNC_2 | CORDIC_CSR_FUNC_1 | CORDIC_CSR_FUNC_0))/*!< Hyperbolic Arctangent */
- #define CORDIC_FUNCTION_NATURALLOG ((uint32_t)(CORDIC_CSR_FUNC_3)) /*!< Natural Logarithm */
- #define CORDIC_FUNCTION_SQUAREROOT ((uint32_t)(CORDIC_CSR_FUNC_3 | CORDIC_CSR_FUNC_0))
Dostępne są funkcje sin, cos, faza, modulo, arcus tangens, funckje hiperboliczne, algorytm naturalny czy pierwiastek.
Kolejnym parametrem jest skalowanie:
- /* Scale factor value 'n' implies that the input data have been multiplied
- by a factor 2exp(-n), and/or the output data need to be multiplied by 2exp(n). */
- #define CORDIC_SCALE_0 (0x00000000U)
- #define CORDIC_SCALE_1 ((uint32_t)(CORDIC_CSR_SCALE_0))
- #define CORDIC_SCALE_2 ((uint32_t)(CORDIC_CSR_SCALE_1))
- #define CORDIC_SCALE_3 ((uint32_t)(CORDIC_CSR_SCALE_1 | CORDIC_CSR_SCALE_0))
- #define CORDIC_SCALE_4 ((uint32_t)(CORDIC_CSR_SCALE_2))
- #define CORDIC_SCALE_5 ((uint32_t)(CORDIC_CSR_SCALE_2 | CORDIC_CSR_SCALE_0))
- #define CORDIC_SCALE_6 ((uint32_t)(CORDIC_CSR_SCALE_2 | CORDIC_CSR_SCALE_1))
- #define CORDIC_SCALE_7 ((uint32_t)(CORDIC_CSR_SCALE_2 | CORDIC_CSR_SCALE_1 | CORDIC_CSR_SCALE_0))
Ten parametr pozwala na zwiększenie zakresu. Wykonuje on przesunięcie wartości w prawo.
Następnie InSize, czyli rozmiar danych wejściowych:
- #define CORDIC_INSIZE_32BITS (0x00000000U) /*!< 32 bits input data size (Q1.31 format) */
- #define CORDIC_INSIZE_16BITS CORDIC_CSR_ARGSIZE /*!< 16 bits input data size (Q1.15 format) */
OutSize, rozmiar danych wyjściowych:
- #define CORDIC_OUTSIZE_32BITS (0x00000000U) /*!< 32 bits output data size (Q1.31 format) */
- #define CORDIC_OUTSIZE_16BITS CORDIC_CSR_RESSIZE /*!< 16 bits output data size (Q1.15 format) */
NbWrite, czyli ilość danych odczytanych w formacie 32 bitowym lub 2x16 bitów, drugie ustawienie przechowuje dwa 32 bitowe dane.
- /*!< One 32-bits write containing either only one 32-bit data input (Q1.31 format), or two 16-bit data input (Q1.15 format) packed in one 32 bits Data */
- #define CORDIC_NBWRITE_1 (0x00000000U)
- /*!< Two 32-bit write containing two 32-bits data input (Q1.31 format) */
- #define CORDIC_NBWRITE_2 CORDIC_CSR_NARGS
NbRead, czyli ilość danych odczytanych w formacie 32 bitowym lub 2x16 bitów, drugie ustawienie przechowuje dwa 32 bitowe dane.
- /*!< One 32-bits read containing either only one 32-bit data output (Q1.31 format), or two 16-bit data output (Q1.15 format) packed in one 32 bits Data */
- #define CORDIC_NBREAD_1 (0x00000000U)
- /*!< Two 32-bit Data containing two 32-bits data output (Q1.31 format) */
- #define CORDIC_NBREAD_2 CORDIC_CSR_NRES
Precision, czyli dokładność. Ilość cykli jakie cooprocesor będzie wykonywał w celu osiągnięcia wybranej dokładności.
- #define CORDIC_PRECISION_1CYCLE
- #define CORDIC_PRECISION_2CYCLES
- #define CORDIC_PRECISION_3CYCLES
- #define CORDIC_PRECISION_4CYCLES
- #define CORDIC_PRECISION_5CYCLES
- #define CORDIC_PRECISION_6CYCLES
- #define CORDIC_PRECISION_7CYCLES
- #define CORDIC_PRECISION_8CYCLES
- #define CORDIC_PRECISION_9CYCLES
- #define CORDIC_PRECISION_10CYCLES
- #define CORDIC_PRECISION_11CYCLES
- #define CORDIC_PRECISION_12CYCLES
- #define CORDIC_PRECISION_13CYCLES
- #define CORDIC_PRECISION_14CYCLES
- #define CORDIC_PRECISION_15CYCLES
Zwracana parametry z funkcji:
- typedef enum
- {
- HAL_CORDIC_STATE_RESET = 0x00U, /*!< CORDIC not yet initialized or disabled */
- HAL_CORDIC_STATE_READY = 0x01U, /*!< CORDIC initialized and ready for use */
- HAL_CORDIC_STATE_BUSY = 0x02U, /*!< CORDIC internal process is ongoing */
- HAL_CORDIC_STATE_ERROR = 0x03U /*!< CORDIC error state */
- } HAL_CORDIC_StateTypeDef;
Do obsługi, biblioteka HAL udostępnia następujące funkcje:
- HAL_StatusTypeDef HAL_CORDIC_Init(CORDIC_HandleTypeDef *hcordic);
- HAL_StatusTypeDef HAL_CORDIC_DeInit(CORDIC_HandleTypeDef *hcordic);
- //----------------------------------------------------------------------
- void HAL_CORDIC_MspInit(CORDIC_HandleTypeDef *hcordic);
- void HAL_CORDIC_MspDeInit(CORDIC_HandleTypeDef *hcordic);
- //----------------------------------------------------------------------
- HAL_StatusTypeDef HAL_CORDIC_Configure(CORDIC_HandleTypeDef *hcordic, const CORDIC_ConfigTypeDef *sConfig);
- HAL_StatusTypeDef HAL_CORDIC_Calculate(CORDIC_HandleTypeDef *hcordic, const int32_t *pInBuff, int32_t *pOutBuff, uint32_t NbCalc, uint32_t Timeout);
- HAL_StatusTypeDef HAL_CORDIC_CalculateZO(CORDIC_HandleTypeDef *hcordic, const int32_t *pInBuff, int32_t *pOutBuff, uint32_t NbCalc, uint32_t Timeout);
- HAL_StatusTypeDef HAL_CORDIC_Calculate_IT(CORDIC_HandleTypeDef *hcordic, const int32_t *pInBuff, int32_t *pOutBuff, uint32_t NbCalc);
- HAL_StatusTypeDef HAL_CORDIC_Calculate_DMA(CORDIC_HandleTypeDef *hcordic, const int32_t *pInBuff, int32_t *pOutBuff, uint32_t NbCalc, uint32_t DMADirection);
Na samym początku musimy uzupełnić strukturę konfiguracyjną:
Dalej można wykonywać obliczenia, czy to z użyciem funkcji standardowej, bądź w przerwaniach, bądź z użyciem DMA.
Przy porównywaniu wyników należy pamiętać, że będą one odbierać od wartości. Z tego powodu należy dobrać deltę, czyli wartość o jaką wynik obliczony będzie się różnił od wartości zadanej.
Dane zapisane są w formacie Q1.31. Gdzie długość danych wynosi 32 bity. Jeden bit wartość znaku, 31 bitów wartość ułamkowa. Funkcje sinus oraz cosinus przyjmują wartości z przedziału od 1 do -1. Wobec tego w tym formacie, będzie można uzyskać największą dokładność.
- static float ANGLES_Raw[128] =
- {
- 0, 0.015625, 0.03125, 0.046875, 0.0625, 0.078125,
- 0.09375, 0.109375, 0.125, 0.140625, 0.15625,
- 0.171875, 0.1875, 0.203125, 0.21875, 0.234375,
- 0.25, 0.265625, 0.28125, 0.296875, 0.3125,
- 0.328125, 0.34375, 0.359375, 0.375, 0.390625,
- 0.40625, 0.421875, 0.4375, 0.453125, 0.46875,
- 0.484375, 0.5, 0.515625, 0.53125, 0.546875,
- 0.5625, 0.578125, 0.59375, 0.609375, 0.625,
- 0.640625, 0.65625, 0.671875, 0.6875, 0.703125,
- 0.71875, 0.734375, 0.75, 0.765625, 0.78125,
- 0.796875, 0.8125, 0.828125, 0.84375, 0.859375,
- 0.875, 0.890625, 0.90625, 0.921875, 0.9375,
- 0.953125, 0.96875, 0.984375,
- -1, -0.984375, -0.96875, -0.953125, -0.9375,
- -0.921875, -0.90625, -0.890625, -0.875, -0.859375,
- -0.84375, -0.828125, -0.8125, -0.796875, -0.78125,
- -0.765625, -0.75, -0.734375, -0.71875, -0.703125,
- -0.6875, -0.671875, -0.65625, -0.640625, -0.625,
- -0.609375, -0.59375, -0.578125, -0.5625, -0.546875,
- -0.53125, -0.515625, -0.5, -0.484375, -0.46875,
- -0.453125, -0.4375, -0.421875, -0.40625, -0.390625,
- -0.375, -0.359375, -0.34375, -0.328125, -0.3125,
- -0.296875, -0.28125, -0.265625, -0.25, -0.234375,
- -0.21875, -0.203125, -0.1875, -0.171875, -0.15625,
- -0.140625, -0.125, -0.109375, -0.09375, -0.078125,
- -0.0625, -0.046875, -0.03125, -0.015625
- };
Do zamiany wartości float na Q1.31 wykorzystuję następującą funkcję:
- static inline int f32_to_q31(double input)
- {
- const float Q31_MAX_F = 0x0.FFFFFFp0F;
- const float Q31_MIN_F = -1.0F;
- return (int)roundf(scalbnf(fmaxf(fminf(input, Q31_MAX_F), Q31_MIN_F), 31));
- }
Zamiana w drugą stroną umożliwia makro:
- #define q31_to_f32(x) ldexp((int32_t)x, -31)
Opisana wyżej tablica po zmianie na format Q1.31 przyjmuje następującą postać:
- static int32_t ANGLES_Q1_31[128] = {
- 0x00000000, 0x02000000, 0x04000000, 0x06000000, 0x08000000,
- 0x0a000000, 0x0c000000, 0x0e000000, 0x10000000, 0x12000000,
- 0x14000000, 0x16000000, 0x18000000, 0x1a000000, 0x1c000000,
- 0x1e000000, 0x20000000, 0x22000000, 0x24000000, 0x26000000,
- 0x28000000, 0x2a000000, 0x2c000000, 0x2e000000, 0x30000000,
- 0x32000000, 0x34000000, 0x36000000, 0x38000000, 0x3a000000,
- 0x3c000000, 0x3e000000, 0x40000000, 0x42000000, 0x44000000,
- 0x46000000, 0x48000000, 0x4a000000, 0x4c000000, 0x4e000000,
- 0x50000000, 0x52000000, 0x54000000, 0x56000000, 0x58000000,
- 0x5a000000, 0x5c000000, 0x5e000000, 0x60000000, 0x62000000,
- 0x64000000, 0x66000000, 0x68000000, 0x6a000000, 0x6c000000,
- 0x6e000000, 0x70000000, 0x72000000, 0x74000000, 0x76000000,
- 0x78000000, 0x7a000000, 0x7c000000, 0x7e000000, 0x80000000,
- 0x82000000, 0x84000000, 0x86000000, 0x88000000, 0x8a000000,
- 0x8c000000, 0x8e000000, 0x90000000, 0x92000000, 0x94000000,
- 0x96000000, 0x98000000, 0x9a000000, 0x9c000000, 0x9e000000,
- 0xa0000000, 0xa2000000, 0xa4000000, 0xa6000000, 0xa8000000,
- 0xaa000000, 0xac000000, 0xae000000, 0xb0000000, 0xb2000000,
- 0xb4000000, 0xb6000000, 0xb8000000, 0xba000000, 0xbc000000,
- 0xbe000000, 0xc0000000, 0xc2000000, 0xc4000000, 0xc6000000,
- 0xc8000000, 0xca000000, 0xcc000000, 0xce000000, 0xd0000000,
- 0xd2000000, 0xd4000000, 0xd6000000, 0xd8000000, 0xda000000,
- 0xdc000000, 0xde000000, 0xe0000000, 0xe2000000, 0xe4000000,
- 0xe6000000, 0xe8000000, 0xea000000, 0xec000000, 0xee000000,
- 0xf0000000, 0xf2000000, 0xf4000000, 0xf6000000, 0xf8000000,
- 0xfa000000, 0xfc000000, 0xfe000000
- };
Obliczenia wartości wykonujemy w następujący sposób (bez użycia DMA):
- MX_CORDIC_Init();
- /* USER CODE BEGIN 2 */
- Cordic_Config_t.Function = CORDIC_FUNCTION_SINE;
- Cordic_Config_t.Scale = CORDIC_SCALE_0;
- Cordic_Config_t.InSize = CORDIC_INSIZE_32BITS;
- Cordic_Config_t.OutSize = CORDIC_OUTSIZE_32BITS;
- Cordic_Config_t.NbRead = CORDIC_NBWRITE_1;
- Cordic_Config_t.NbWrite = CORDIC_NBREAD_1;
- Cordic_Config_t.Precision = CORDIC_PRECISION_8CYCLES;
- if (HAL_CORDIC_Configure(&hcordic, &Cordic_Config_t) != HAL_OK)
- {
- Error_Handler();
- }
- if (HAL_CORDIC_Calculate(&hcordic,
- ANGLES_Q1_31,
- aCalculatedSinQ1_31,
- 128,
- CORDIC_DMA_DIR_IN_OUT) != HAL_OK)
- {
- Error_Handler();
- }
- while (HAL_CORDIC_GetState(&hcordic) != HAL_CORDIC_STATE_READY)
- { }
W przykładzie udostępnionym przez firmę ST stosowana jest dodatkowo funkcja:
- SCB_CleanInvalidateDCache_by_Addr((uint32_t*)&aCalculatedSinQ1_31, sizeof(aCalculatedSinQ1_31));
Jej zadaniem jest czyszczenie pamięci cache. Jest ona konieczna podczas korzystania z DMA.
Obliczone dane są następujące:
- static int32_t aCalculatedSinQ1_31[128] =
- {
- 0x00000600, 0x0647da00, 0x0c8bd600, 0x12c81300,
- 0x18f8b700, 0x1f19fa00, 0x25280600, 0x2b1f3200,
- 0x30fbc900, 0x36ba1c00, 0x3c56b400, 0x41ce2100,
- 0x471cec00, 0x4c3fdd00, 0x5133c500, 0x55f5a000,
- 0x5a827600, 0x5ed77900, 0x62f20600, 0x66cf8400,
- 0x6a6d9900, 0x6dca0800, 0x70e2ca00, 0x73b5ec00,
- 0x7641ac00, 0x78848200, 0x7a7d0700, 0x7c29fa00,
- 0x7d8a5a00, 0x7e9d4e00, 0x7f623100, 0x7fd88300,
- 0x7fffff00, 0x7fd88300, 0x7f623200, 0x7e9d4f00,
- 0x7d8a5b00, 0x7c29f900, 0x7a7d0800, 0x78848200,
- 0x7641a800, 0x73b5ec00, 0x70e2cb00, 0x6dca0600,
- 0x6a6d9900, 0x66cf8400, 0x62f20400, 0x5ed77900,
- 0x5a827a00, 0x55f5a100, 0x5133c400, 0x4c3fde00,
- 0x471ced00, 0x41ce2000, 0x3c56b500, 0x36ba1d00,
- 0x30fbc400, 0x2b1f3200, 0x25280500, 0x1f19f300,
- 0x18f8b400, 0x12c81000, 0x0c8bd300, 0x0647d900,
- 0xfffffa00, 0xf9b82600, 0xf3742a00, 0xed37ed00,
- 0xe7074900, 0xe0e60600, 0xdad7fa00, 0xd4e0ce00,
- 0xcf043700, 0xc945e400, 0xc3a94c00, 0xbe31df00,
- 0xb8e31400, 0xb3c02300, 0xaecc3b00, 0xaa0a6000,
- 0xa57d8a00, 0xa1288700, 0x9d0dfa00, 0x99307c00,
- 0x95926700, 0x9235f800, 0x8f1d3600, 0x8c4a1400,
- 0x89be5400, 0x877b7e00, 0x8582f900, 0x83d60600,
- 0x8275a600, 0x8162b200, 0x809dcf00, 0x80277d00,
- 0x80000100, 0x80277d00, 0x809dce00, 0x8162b100,
- 0x8275a500, 0x83d60700, 0x8582f800, 0x877b7e00,
- 0x89be5800, 0x8c4a1400, 0x8f1d3500, 0x9235fa00,
- 0x95926700, 0x99307c00, 0x9d0dfc00, 0xa1288700,
- 0xa57d8600, 0xaa0a5f00, 0xaecc3c00, 0xb3c02200,
- 0xb8e31300, 0xbe31e000, 0xc3a94b00, 0xc945e300,
- 0xcf043c00, 0xd4e0ce00, 0xdad7fb00, 0xe0e60d00,
- 0xe7074c00, 0xed37f000, 0xf3742d00, 0xf9b82700,
- };
Całość można następnie zamienić na format float lub porównywać bezpośrednio z wartościami w formacie Q1..31.
Jak widać dane mają odchyłkę od wartości referencyjnych. W celu dokładnej weryfikacji trzeba dobrać dopuszczalny poziom błędu.
Z wykorzystaniem DMA całość wygląda następująco:
- Cordic_Config_t.Function = CORDIC_FUNCTION_SINE;
- Cordic_Config_t.Scale = CORDIC_SCALE_0;
- Cordic_Config_t.InSize = CORDIC_INSIZE_32BITS;
- Cordic_Config_t.OutSize = CORDIC_OUTSIZE_32BITS;
- Cordic_Config_t.NbRead = CORDIC_NBWRITE_1;
- Cordic_Config_t.NbWrite = CORDIC_NBREAD_1;
- Cordic_Config_t.Precision = CORDIC_PRECISION_6CYCLES;
- if (HAL_CORDIC_Configure(&hcordic, &Cordic_Config_t) != HAL_OK)
- {
- Error_Handler();
- }
- if (HAL_CORDIC_Calculate_DMA(&hcordic, ANGLES_Q1_31, aCalculatedSinQ1_31,
- sizeof(ANGLES_Q1_31)/sizeof(ANGLES_Q1_31[0]), CORDIC_DMA_DIR_IN_OUT) != HAL_OK)
- {
- Error_Handler();
- }
- while (HAL_CORDIC_GetState(&hcordic) != HAL_CORDIC_STATE_READY) { }
- SCB_CleanInvalidateDCache_by_Addr((uint32_t*)&aCalculatedSinQ1_31, sizeof(aCalculatedSinQ1_31));
Należy tutaj jeszcze pamiętać o poprawnej inicjalizacji DMA:
- void HAL_CORDIC_MspInit(CORDIC_HandleTypeDef* hcordic)
- {
- if(hcordic->Instance==CORDIC)
- {
- /* Peripheral clock enable */
- __HAL_RCC_CORDIC_CLK_ENABLE();
- /* CORDIC DMA Init */
- /* CORDIC_WRITE Init */
- hdma_cordic_write.Instance = DMA1_Stream0;
- hdma_cordic_write.Init.Request = DMA_REQUEST_CORDIC_WRITE;
- hdma_cordic_write.Init.Direction = DMA_MEMORY_TO_PERIPH;
- hdma_cordic_write.Init.PeriphInc = DMA_PINC_DISABLE;
- hdma_cordic_write.Init.MemInc = DMA_MINC_ENABLE;
- hdma_cordic_write.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
- hdma_cordic_write.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
- hdma_cordic_write.Init.Mode = DMA_NORMAL;
- hdma_cordic_write.Init.Priority = DMA_PRIORITY_LOW;
- if (HAL_DMA_Init(&hdma_cordic_write) != HAL_OK)
- {
- Error_Handler();
- }
- __HAL_LINKDMA(hcordic,hdmaIn,hdma_cordic_write);
- /* CORDIC_READ Init */
- hdma_cordic_read.Instance = DMA1_Stream1;
- hdma_cordic_read.Init.Request = DMA_REQUEST_CORDIC_READ;
- hdma_cordic_read.Init.Direction = DMA_PERIPH_TO_MEMORY;
- hdma_cordic_read.Init.PeriphInc = DMA_PINC_DISABLE;
- hdma_cordic_read.Init.MemInc = DMA_MINC_ENABLE;
- hdma_cordic_read.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
- hdma_cordic_read.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
- hdma_cordic_read.Init.Mode = DMA_NORMAL;
- hdma_cordic_read.Init.Priority = DMA_PRIORITY_LOW;
- if (HAL_DMA_Init(&hdma_cordic_read) != HAL_OK)
- {
- Error_Handler();
- }
- __HAL_LINKDMA(hcordic,hdmaOut,hdma_cordic_read);
- }
- }