// Author: https://github.com/MajicDesigns/MD_AD9833 #include "main.h" #include "ad9833_def.h" #include "ad9833.h" // Convenience calculations // static uint32_t ad9833_calcFreq(float f); // Calculate AD9833 frequency register from a frequency // static uint16_t ad9833_calcPhase(float a); // Calculate AD9833 phase register from phase void ad9833_spi_activate(ad9833_handle_t *hfg) { HAL_GPIO_WritePin(hfg->cs_port, hfg->cs_pin, GPIO_PIN_RESET); } void ad9833_spi_deactivate(ad9833_handle_t *hfg) { HAL_GPIO_WritePin(hfg->cs_port, hfg->cs_pin, GPIO_PIN_SET); } static void ad9833_transmit16(ad9833_handle_t *hfg, uint16_t data) { uint8_t data8; ad9833_spi_activate(hfg); data8 = (uint8_t)((data >> 8) & 0x00FF); HAL_SPI_Transmit(hfg->hspi, &data8, 1, HAL_MAX_DELAY); data8 = (uint8_t)(data & 0x00FF); HAL_SPI_Transmit(hfg->hspi, &data8, 1, HAL_MAX_DELAY); ad9833_spi_deactivate(hfg); } void ad9833_reset(ad9833_handle_t *hfg, uint8_t hold) // Reset is done on a 1 to 0 transition { hfg->_regCtl |= (1 << AD_RESET); ad9833_transmit16(hfg, hfg->_regCtl); if (!hold) { hfg->_regCtl &= ~(1 << AD_RESET); ad9833_transmit16(hfg, hfg->_regCtl); } } void ad9833_init(ad9833_handle_t *hfg, SPI_HandleTypeDef *hspi, GPIO_TypeDef *cs_port, uint16_t cs_pin) // Initialise the AD9833 and then set up safe values for the AD9833 device // Procedure from Figure 27 of in the AD9833 Data Sheet { // initialise our preferred CS pin (could be same as SS) hfg->hspi = hspi; hfg->cs_port = cs_port; hfg->cs_pin = cs_pin; HAL_GPIO_WritePin(hfg->cs_port, hfg->cs_pin, GPIO_PIN_SET); hfg->_regCtl = 0; hfg->_regCtl |= (1 << AD_B28); // always write 2 words consecutively for frequency ad9833_transmit16(hfg, hfg->_regCtl); ad9833_reset(hfg, 1); // Reset and hold ad9833_setFrequency(hfg, CHAN_0, AD_DEFAULT_FREQ); ad9833_setFrequency(hfg, CHAN_1, AD_DEFAULT_FREQ); ad9833_setPhase(hfg, CHAN_0, AD_DEFAULT_PHASE); ad9833_setPhase(hfg, CHAN_1, AD_DEFAULT_PHASE); ad9833_setActiveChannelPhase(hfg, CHAN_0); ad9833_setActiveChannelFreq(hfg, CHAN_0); ad9833_setMode(hfg, MODE_OFF); ad9833_reset(hfg, 0); // full transition } void ad9833_setActiveChannelFreq(ad9833_handle_t *hfg, AD_channel_t chan) { // PRINT("\nsetActiveFreq CHAN_", chan); switch (chan) { case CHAN_0: hfg->_regCtl &= ~(1 << AD_FSELECT); break; case CHAN_1: hfg->_regCtl |= (1 << AD_FSELECT); break; } ad9833_transmit16(hfg, hfg->_regCtl); } AD_channel_t ad9833_getActiveChannelFreq(ad9833_handle_t *hfg) { return (hfg->_regCtl & (1 << AD_FSELECT)) ? CHAN_1 : CHAN_0; }; void ad9833_setActiveChannelPhase(ad9833_handle_t *hfg, AD_channel_t chan) { // PRINT("\nsetActivePhase CHAN_", chan); switch (chan) { case CHAN_0: hfg->_regCtl &= ~(1 << AD_PSELECT); break; case CHAN_1: hfg->_regCtl |= (1 << AD_PSELECT); break; } ad9833_transmit16(hfg, hfg->_regCtl); } AD_channel_t ad9833_getActiveChannelPhase(ad9833_handle_t *hfg) { return (hfg->_regCtl & (1 << AD_PSELECT)) ? CHAN_1 : CHAN_0; }; void ad9833_setMode(ad9833_handle_t *hfg, AD_mode_t mode) { // PRINTS("\nsetWave "); hfg->_mode = mode; switch (mode) { case MODE_OFF: hfg->_regCtl &= ~(1 << AD_OPBITEN); hfg->_regCtl &= ~(1 << AD_MODE); hfg->_regCtl |= (1 << AD_SLEEP1); hfg->_regCtl |= (1 << AD_SLEEP12); break; case MODE_SINE: hfg->_regCtl &= ~(1 << AD_OPBITEN); hfg->_regCtl &= ~(1 << AD_MODE); hfg->_regCtl &= ~(1 << AD_SLEEP1); hfg->_regCtl &= ~(1 << AD_SLEEP12); break; case MODE_SQUARE1: hfg->_regCtl |= (1 << AD_OPBITEN); hfg->_regCtl &= ~(1 << AD_MODE); hfg->_regCtl |= (1 << AD_DIV2); hfg->_regCtl &= ~(1 << AD_SLEEP1); hfg->_regCtl &= ~(1 << AD_SLEEP12); break; case MODE_SQUARE2: hfg->_regCtl |= (1 << AD_OPBITEN); hfg->_regCtl &= ~(1 << AD_MODE); hfg->_regCtl &= ~(1 << AD_DIV2); hfg->_regCtl &= ~(1 << AD_SLEEP1); hfg->_regCtl &= ~(1 << AD_SLEEP12); break; case MODE_TRIANGLE: hfg->_regCtl &= ~(1 << AD_OPBITEN); hfg->_regCtl |= (1 << AD_MODE); hfg->_regCtl &= ~(1 << AD_SLEEP1); hfg->_regCtl &= ~(1 << AD_SLEEP12); break; } ad9833_transmit16(hfg, hfg->_regCtl); } // static uint32_t ad9833_calcFreq(float f) // // Calculate register value for AD9833 frequency register from a frequency // { // return (uint32_t)((f * AD_2POW28 / AD_MCLK) + 0.5f); // } static uint32_t ad9833_calcFreq_uint(uint32_t f) { return ((f * AD_2POW28 + AD_MCLK_DIV2) / AD_MCLK); // ((n + d/2)/d) } // static uint16_t ad9833_calcPhase(float a) // // Calculate the value for AD9833 phase register from given phase in tenths of a degree // { // return (uint16_t)((512.0f * (a / 10) / 45) + 0.5f); // } static uint16_t ad9833_calcPhase_uint(uint16_t p) { return ((p * 4096U + 180) / 360); } void ad9833_setFrequency(ad9833_handle_t *hfg, AD_channel_t chan, uint32_t freq) { // PRINT("\nsetFreq CHAN_", chan); uint16_t freq_channel = 0; hfg->_freq[chan] = freq; hfg->_regFreq[chan] = ad9833_calcFreq_uint(freq); // select the address mask switch (chan) { case CHAN_0: freq_channel = SEL_FREQ0; break; case CHAN_1: freq_channel = SEL_FREQ1; break; default: // error break; } // Assumes B28 is on so we can send consecutive words // B28 is set by default for the library, so just send it here // Now send the two parts of the frequency 14 bits at a time, // LSBs first // spiSend(_regCtl); // set B28 ad9833_transmit16(hfg, freq_channel | (uint16_t)(hfg->_regFreq[chan] & 0x3fff)); ad9833_transmit16(hfg, freq_channel | (uint16_t)((hfg->_regFreq[chan] >> 14) & 0x3fff)); } void ad9833_setPhase(ad9833_handle_t *hfg, AD_channel_t chan, uint16_t phase) { // PRINT("\nsetPhase CHAN_", chan); uint16_t phase_channel = 0; hfg->_phase[chan] = phase; hfg->_regPhase[chan] = ad9833_calcPhase_uint(phase); // select the address mask switch (chan) { case CHAN_0: phase_channel = SEL_PHASE0; break; case CHAN_1: phase_channel = SEL_PHASE1; break; default: // error break; } // Now send the phase as 12 bits with appropriate address bits ad9833_transmit16(hfg, phase_channel | (0xfff & hfg->_regPhase[chan])); }