235 lines
5.9 KiB
C
235 lines
5.9 KiB
C
// 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);
|
|
hfg->hcs->cs_on(hfg->hcs);
|
|
}
|
|
|
|
void ad9833_spi_deactivate(ad9833_handle_t *hfg)
|
|
{
|
|
// HAL_GPIO_WritePin(hfg->cs_port, hfg->cs_pin, GPIO_PIN_SET);
|
|
hfg->hcs->cs_off(hfg->hcs);
|
|
}
|
|
|
|
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, cs_handle_t *hcs)
|
|
// 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->hcs = hcs;
|
|
|
|
hfg->hcs->cs_off(hfg->hcs);
|
|
|
|
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->_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->_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]));
|
|
} |