237 lines
		
	
	
		
			6.0 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			237 lines
		
	
	
		
			6.0 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);
 | |
| }
 | |
| 
 | |
| 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]));
 | |
| } |