added drivers

This commit is contained in:
2023-09-25 21:32:15 +02:00
parent 0d74fea761
commit 4829b04024
28 changed files with 6621 additions and 3 deletions

235
app/drivers/ad9833/ad9833.c Normal file
View File

@@ -0,0 +1,235 @@
// 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]));
}

View File

@@ -0,0 +1,58 @@
#pragma once
#include "spi_cs_if.h"
#define AD_DEFAULT_FREQ 1000U ///< Default initialisation frequency (Hz)
#define AD_DEFAULT_PHASE 0 ///< Default initialisation phase angle (degrees)
#define AD_MCLK 25000000U ///< Clock speed of the AD9833 reference clock in Hz
#define AD_MCLK_DIV2 12500000U ///< Clock speed of the AD9833 reference clock in Hz
/**
* Channel enumerated type.
*
* This enumerated type is used with the to specify which channel
* is being invoked on operations that could be channel related.
*/
typedef enum
{
CHAN_0 = 0, ///< Channel 0 definition
CHAN_1 = 1, ///< Channel 1 definition
} AD_channel_t;
/**
* Output mode request enumerated type.
*
* This enumerated type is used with the \ref setMode() methods to identify
* the mode request.
*/
typedef enum
{
MODE_OFF, ///< Set output all off
MODE_SINE, ///< Set output to a sine wave at selected frequency
MODE_SQUARE1, ///< Set output to a square wave at selected frequency
MODE_SQUARE2, ///< Set output to a square wave at half selected frequency
MODE_TRIANGLE, ///< Set output to a triangle wave at selected frequency
} AD_mode_t;
typedef struct
{
uint16_t _regCtl; // control register image
uint32_t _regFreq[2]; // frequency registers
uint32_t _regPhase[2]; // phase registers
AD_mode_t _mode; // last set mode
SPI_HandleTypeDef *hspi;
cs_handle_t *hcs;
} ad9833_handle_t;
void ad9833_init(ad9833_handle_t *hfg, SPI_HandleTypeDef *hspi, cs_handle_t *hcs);
void ad9833_spi_activate(ad9833_handle_t *hfg);
void ad9833_spi_deactivate(ad9833_handle_t *hfg);
void ad9833_reset(ad9833_handle_t *hfg, uint8_t hold);
void ad9833_setActiveChannelFreq(ad9833_handle_t *hfg, AD_channel_t chan);
AD_channel_t ad9833_getActiveChannelFreq(ad9833_handle_t *hfg);
void ad9833_setActiveChannelPhase(ad9833_handle_t *hfg, AD_channel_t chan);
AD_channel_t ad9833_getActiveChannelPhase(ad9833_handle_t *hfg);
void ad9833_setMode(ad9833_handle_t *hfg, AD_mode_t mode);
void ad9833_setFrequency(ad9833_handle_t *hfg, AD_channel_t chan, uint32_t freq);
void ad9833_setPhase(ad9833_handle_t *hfg, AD_channel_t chan, uint16_t phase);

View File

@@ -0,0 +1,44 @@
// Author: https://github.com/MajicDesigns/MD_AD9833
#pragma once
/** @}*/
// AD9833 Control Register bit definitions
#define AD_B28 13 ///< B28 = 1 allows a complete word to be loaded into a frequency register in
///< two consecutive writes. When B28 = 0, the 28-bit frequency register
///< operates as two 14-bit registers.
#define AD_HLB 12 ///< Control bit allows the user to continuously load the MSBs or LSBs of a
///< frequency register while ignoring the remaining 14 bits. HLB is used
///< in conjunction with B28; when B28 = 1, this control bit is ignored.
#define AD_FSELECT 11 ///< Defines whether the FREQ0 register or the FREQ1 register is used in
///< the phase accumulator.
#define AD_PSELECT 10 ///< Defines whether the PHASE0 register or the PHASE1 register data is
///< added to the output of the phase accumulator.
#define AD_RESET 8 ///< Reset = 1 resets internal registers to 0, which corresponds to an
///< analog output of midscale. Reset = 0 disables reset.
#define AD_SLEEP1 7 ///< When SLEEP1 = 1, the internal MCLK clock is disabled, and the DAC output
///< remains at its present value. When SLEEP1 = 0, MCLK is enabled.
#define AD_SLEEP12 6 ///< SLEEP12 = 1 powers down the on-chip DAC. SLEEP12 = 0 implies that
///< the DAC is active.
#define AD_OPBITEN 5 ///< When OPBITEN = 1, the output of the DAC is no longer available at the
///< VOUT pin, replaced by MSB (or MSB/2) of the DAC. When OPBITEN = 0, the
///< DAC is connected to VOUT.
#define AD_DIV2 3 ///< When DIV2 = 1, the MSB of the DAC data is passed to the VOUT pin. When
///< DIV2 = 0, the MSB/2 of the DAC data is output at the VOUT pin.
#define AD_MODE 1 ///< When MODE = 1, the SIN ROM is bypassed, resulting in a triangle output
///< from the DAC. When MODE = 0, the SIN ROM is used which results in a
///< sinusoidal signal at the output.
// AD9833 Frequency and Phase register bit definitions
#define AD_FREQ1 15 ///< Select frequency 1 register
#define AD_FREQ0 14 ///< Select frequency 0 register
#define AD_PHASE 13 ///< Select the phase register
// AD9833 Freq and Phase register address identifiers
#define SEL_FREQ0 (1 << AD_FREQ0)
#define SEL_FREQ1 (1 << AD_FREQ1)
#define SEL_PHASE0 (1 << AD_FREQ0 | 1 << AD_FREQ1 | 0 << AD_PHASE)
#define SEL_PHASE1 (1 << AD_FREQ0 | 1 << AD_FREQ1 | 1 << AD_PHASE)
// AD9833 frequency and phase calculation macros
#define AD_2POW28 (1ULL << 28) ///< Used when calculating output frequency