basic static DAC
This commit is contained in:
@@ -0,0 +1,40 @@
|
||||
//
|
||||
// Created by MightyPork on 2018/02/03.
|
||||
//
|
||||
|
||||
#include "platform.h"
|
||||
#include "unit_base.h"
|
||||
#include "unit_dac.h"
|
||||
|
||||
#define DAC_INTERNAL
|
||||
#include "_dac_internal.h"
|
||||
|
||||
/**
|
||||
* Re-configure the
|
||||
* @param unit
|
||||
*/
|
||||
void UDAC_Reconfigure(Unit *unit)
|
||||
{
|
||||
struct priv *priv = unit->data;
|
||||
|
||||
DAC->CR &= ~(DAC_CR_EN1 | DAC_CR_EN2);
|
||||
uint32_t CR = 0;
|
||||
if (priv->cfg.ch1.enable) {
|
||||
CR |=
|
||||
(priv->cfg.ch1.buffered ? 0 : DAC_CR_BOFF1) |
|
||||
(priv->cfg.ch1.noise_type << DAC_CR_WAVE1_Pos) |
|
||||
(priv->cfg.ch1.noise_level & 0xF) << DAC_CR_MAMP1_Pos |
|
||||
(0b111 << DAC_CR_TSEL1_Pos); // software trigger;
|
||||
|
||||
CR |= DAC_CR_EN1;
|
||||
}
|
||||
if (priv->cfg.ch2.enable) {
|
||||
CR |=
|
||||
(priv->cfg.ch2.buffered ? 0 : DAC_CR_BOFF2) |
|
||||
(priv->cfg.ch2.noise_type << DAC_CR_WAVE2_Pos) |
|
||||
(priv->cfg.ch2.noise_level & 0xF) << DAC_CR_MAMP2_Pos |
|
||||
(0b111 << DAC_CR_TSEL2_Pos); // software trigger
|
||||
CR |= DAC_CR_EN2;
|
||||
}
|
||||
DAC->CR = CR;
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
//
|
||||
// Created by MightyPork on 2018/02/03.
|
||||
//
|
||||
|
||||
#include "platform.h"
|
||||
#include "unit_base.h"
|
||||
|
||||
#define DAC_INTERNAL
|
||||
#include "_dac_internal.h"
|
||||
|
||||
/** Allocate data structure and set defaults */
|
||||
error_t UDAC_preInit(Unit *unit)
|
||||
{
|
||||
struct priv *priv = unit->data = calloc_ck(1, sizeof(struct priv));
|
||||
if (priv == NULL) return E_OUT_OF_MEM;
|
||||
|
||||
priv->cfg.ch1.buffered = true;
|
||||
priv->cfg.ch1.enable = true;
|
||||
priv->cfg.ch1.noise_level = 2;
|
||||
priv->cfg.ch1.noise_type = NOISE_NONE;
|
||||
|
||||
priv->ch1.noise_type = priv->cfg.ch1.noise_type;
|
||||
priv->ch1.noise_level = priv->cfg.ch1.noise_level;
|
||||
|
||||
priv->cfg.ch2.buffered = true;
|
||||
priv->cfg.ch2.enable = true;
|
||||
priv->cfg.ch2.noise_level = 2;
|
||||
priv->cfg.ch2.noise_type = NOISE_NONE;
|
||||
|
||||
priv->ch2.noise_type = priv->cfg.ch2.noise_type;
|
||||
priv->ch2.noise_level = priv->cfg.ch2.noise_level;
|
||||
|
||||
return E_SUCCESS;
|
||||
}
|
||||
|
||||
/** Finalize unit set-up */
|
||||
error_t UDAC_init(Unit *unit)
|
||||
{
|
||||
bool suc = true;
|
||||
struct priv *priv = unit->data;
|
||||
|
||||
// this may change for different devices
|
||||
const Resource r_ch1 = R_PA4;
|
||||
const Resource r_ch2 = R_PA5;
|
||||
|
||||
const bool e1 = priv->cfg.ch1.enable;
|
||||
const bool e2 = priv->cfg.ch2.enable;
|
||||
|
||||
|
||||
if (e1) {
|
||||
TRY(rsc_claim(unit, r_ch1));
|
||||
}
|
||||
|
||||
if (e2) {
|
||||
TRY(rsc_claim(unit, r_ch2));
|
||||
}
|
||||
|
||||
TRY(rsc_claim(unit, R_DAC1));
|
||||
|
||||
// ensure the peripheral is clean (this may be redundant)
|
||||
__HAL_RCC_DAC1_FORCE_RESET();
|
||||
__HAL_RCC_DAC1_RELEASE_RESET();
|
||||
|
||||
hw_periph_clock_enable(DAC1);
|
||||
|
||||
GPIO_TypeDef *port;
|
||||
uint32_t ll;
|
||||
if (e1) {
|
||||
assert_param(hw_pinrsc2ll(r_ch1, &port, &ll));
|
||||
LL_GPIO_SetPinMode(port, ll, LL_GPIO_MODE_ANALOG);
|
||||
}
|
||||
if (e2) {
|
||||
assert_param(hw_pinrsc2ll(r_ch1, &port, &ll));
|
||||
LL_GPIO_SetPinMode(port, ll, LL_GPIO_MODE_ANALOG);
|
||||
}
|
||||
|
||||
UDAC_Reconfigure(unit);
|
||||
|
||||
return E_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/** Tear down the unit */
|
||||
void UDAC_deInit(Unit *unit)
|
||||
{
|
||||
struct priv *priv = unit->data;
|
||||
|
||||
// de-init peripherals
|
||||
if (unit->status == E_SUCCESS ) {
|
||||
LL_DAC_DeInit(DAC);
|
||||
hw_periph_clock_disable(DAC1);
|
||||
}
|
||||
|
||||
// Release all resources, deinit pins
|
||||
rsc_teardown(unit);
|
||||
|
||||
// Free memory
|
||||
free_ck(unit->data);
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
//
|
||||
// Created by MightyPork on 2018/02/03.
|
||||
//
|
||||
|
||||
#ifndef GEX_F072_DAC_INTERNAL_H
|
||||
#define GEX_F072_DAC_INTERNAL_H
|
||||
|
||||
#ifndef DAC_INTERNAL
|
||||
#error bad include!
|
||||
#endif
|
||||
|
||||
#include "unit_base.h"
|
||||
|
||||
enum UDAC_Noise {
|
||||
NOISE_NONE = 0b00,
|
||||
NOISE_WHITE = 0b01,
|
||||
NOISE_TRIANGLE = 0b10,
|
||||
};
|
||||
|
||||
struct udac_channel_cfg {
|
||||
bool enable;
|
||||
bool buffered;
|
||||
enum UDAC_Noise noise_type;
|
||||
uint8_t noise_level; // 0-11
|
||||
};
|
||||
|
||||
struct udac_channel_live {
|
||||
enum UDAC_Noise noise_type;
|
||||
uint8_t noise_level; // 0-11
|
||||
};
|
||||
|
||||
/** Private data structure */
|
||||
struct priv {
|
||||
// settings
|
||||
struct {
|
||||
struct udac_channel_cfg ch1;
|
||||
struct udac_channel_cfg ch2;
|
||||
} cfg;
|
||||
|
||||
// internal state
|
||||
struct udac_channel_live ch1;
|
||||
struct udac_channel_live ch2;
|
||||
TIM_TypeDef *TIMx; // timer used for the DDS function
|
||||
};
|
||||
|
||||
/** Allocate data structure and set defaults */
|
||||
error_t UDAC_preInit(Unit *unit);
|
||||
|
||||
/** Load from a binary buffer stored in Flash */
|
||||
void UDAC_loadBinary(Unit *unit, PayloadParser *pp);
|
||||
|
||||
/** Write to a binary buffer for storing in Flash */
|
||||
void UDAC_writeBinary(Unit *unit, PayloadBuilder *pb);
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/** Parse a key-value pair from the INI file */
|
||||
error_t UDAC_loadIni(Unit *unit, const char *key, const char *value);
|
||||
|
||||
/** Generate INI file section for the unit */
|
||||
void UDAC_writeIni(Unit *unit, IniWriter *iw);
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/** Finalize unit set-up */
|
||||
error_t UDAC_init(Unit *unit);
|
||||
|
||||
/** Tear down the unit */
|
||||
void UDAC_deInit(Unit *unit);
|
||||
|
||||
void UDAC_Reconfigure(Unit *unit);
|
||||
|
||||
#endif //GEX_F072_DAC_INTERNAL_H
|
||||
@@ -0,0 +1,131 @@
|
||||
//
|
||||
// Created by MightyPork on 2018/02/03.
|
||||
//
|
||||
|
||||
#include "platform.h"
|
||||
#include "unit_base.h"
|
||||
|
||||
#define DAC_INTERNAL
|
||||
#include "_dac_internal.h"
|
||||
|
||||
/** Load from a binary buffer stored in Flash */
|
||||
void UDAC_loadBinary(Unit *unit, PayloadParser *pp)
|
||||
{
|
||||
struct priv *priv = unit->data;
|
||||
|
||||
uint8_t version = pp_u8(pp);
|
||||
(void)version;
|
||||
|
||||
priv->cfg.ch1.enable = pp_bool(pp);
|
||||
priv->cfg.ch1.buffered = pp_bool(pp);
|
||||
priv->cfg.ch1.noise_type = (enum UDAC_Noise) pp_u8(pp);
|
||||
priv->cfg.ch1.noise_level = pp_u8(pp);
|
||||
|
||||
priv->cfg.ch2.enable = pp_bool(pp);
|
||||
priv->cfg.ch2.buffered = pp_bool(pp);
|
||||
priv->cfg.ch2.noise_type = (enum UDAC_Noise) pp_u8(pp);
|
||||
priv->cfg.ch2.noise_level = pp_u8(pp);
|
||||
}
|
||||
|
||||
/** Write to a binary buffer for storing in Flash */
|
||||
void UDAC_writeBinary(Unit *unit, PayloadBuilder *pb)
|
||||
{
|
||||
struct priv *priv = unit->data;
|
||||
|
||||
pb_u8(pb, 0); // version
|
||||
|
||||
pb_bool(pb, priv->cfg.ch1.enable);
|
||||
pb_bool(pb, priv->cfg.ch1.buffered);
|
||||
pb_u8(pb, priv->cfg.ch1.noise_type);
|
||||
pb_u8(pb, priv->cfg.ch1.noise_level);
|
||||
|
||||
pb_bool(pb, priv->cfg.ch2.enable);
|
||||
pb_bool(pb, priv->cfg.ch2.buffered);
|
||||
pb_u8(pb, priv->cfg.ch2.noise_type);
|
||||
pb_u8(pb, priv->cfg.ch2.noise_level);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/** Parse a key-value pair from the INI file */
|
||||
error_t UDAC_loadIni(Unit *unit, const char *key, const char *value)
|
||||
{
|
||||
bool suc = true;
|
||||
struct priv *priv = unit->data;
|
||||
|
||||
// Ch1
|
||||
if (streq(key, "ch1_enable")) {
|
||||
priv->cfg.ch1.enable = cfg_bool_parse(value, &suc);
|
||||
}
|
||||
else if (streq(key, "ch1_buff")) {
|
||||
priv->cfg.ch1.buffered = cfg_bool_parse(value, &suc);
|
||||
}
|
||||
else if (streq(key, "ch1_noise")) {
|
||||
priv->cfg.ch1.noise_type =
|
||||
(enum UDAC_Noise) cfg_enum3_parse(value,
|
||||
"NONE", NOISE_NONE,
|
||||
"WHITE", NOISE_WHITE,
|
||||
"TRIANGLE", NOISE_TRIANGLE, &suc);
|
||||
}
|
||||
else if (streq(key, "ch1_noise-level")) {
|
||||
uint8_t x = cfg_u8_parse(value, &suc);
|
||||
if (x == 0) x = 1;
|
||||
if (x > 12) x = 12;
|
||||
priv->cfg.ch1.noise_level = (uint8_t) (x - 1);
|
||||
}
|
||||
// Ch2
|
||||
else if (streq(key, "ch2_enable")) {
|
||||
priv->cfg.ch2.enable = cfg_bool_parse(value, &suc);
|
||||
}
|
||||
else if (streq(key, "ch2_buff")) {
|
||||
priv->cfg.ch2.buffered = cfg_bool_parse(value, &suc);
|
||||
}
|
||||
else if (streq(key, "ch2_noise")) {
|
||||
priv->cfg.ch2.noise_type =
|
||||
(enum UDAC_Noise) cfg_enum3_parse(value,
|
||||
"NONE", NOISE_NONE,
|
||||
"WHITE", NOISE_WHITE,
|
||||
"TRIANGLE", NOISE_TRIANGLE, &suc);
|
||||
}
|
||||
else if (streq(key, "ch2_noise-level")) {
|
||||
uint8_t x = cfg_u8_parse(value, &suc);
|
||||
if (x == 0) x = 1;
|
||||
if (x > 12) x = 12;
|
||||
priv->cfg.ch2.noise_level = (uint8_t) (x - 1);
|
||||
}
|
||||
// end
|
||||
else {
|
||||
return E_BAD_KEY;
|
||||
}
|
||||
|
||||
if (!suc) return E_BAD_VALUE;
|
||||
return E_SUCCESS;
|
||||
}
|
||||
|
||||
/** Generate INI file section for the unit */
|
||||
void UDAC_writeIni(Unit *unit, IniWriter *iw)
|
||||
{
|
||||
struct priv *priv = unit->data;
|
||||
|
||||
iw_comment(iw, "Enabled channels (1:A4, 2:A5)");
|
||||
iw_entry_s(iw, "ch1_enable", str_yn(priv->cfg.ch1.enable));
|
||||
iw_entry_s(iw, "ch2_enable", str_yn(priv->cfg.ch2.enable));
|
||||
|
||||
iw_comment(iw, "Output buffering");
|
||||
iw_entry_s(iw, "ch1_buff", str_yn(priv->cfg.ch1.buffered));
|
||||
iw_entry_s(iw, "ch2_buff", str_yn(priv->cfg.ch2.buffered));
|
||||
|
||||
iw_comment(iw, "Superimposed noise type (NONE,WHITE,TRIANGLE)");
|
||||
iw_entry_s(iw, "ch1_noise", cfg_enum3_encode(priv->cfg.ch1.noise_type,
|
||||
NOISE_NONE, "NONE",
|
||||
NOISE_WHITE, "WHITE",
|
||||
NOISE_TRIANGLE, "TRIANGLE"));
|
||||
iw_entry_s(iw, "ch2_noise", cfg_enum3_encode(priv->cfg.ch2.noise_type,
|
||||
NOISE_NONE, "NONE",
|
||||
NOISE_WHITE, "WHITE",
|
||||
NOISE_TRIANGLE, "TRIANGLE"));
|
||||
|
||||
iw_comment(iw, "Noise amplitude (nbr. of bits,1-12)");
|
||||
iw_entry_d(iw, "ch1_noise-level", priv->cfg.ch1.noise_level + 1);
|
||||
iw_entry_d(iw, "ch2_noise-level", priv->cfg.ch2.noise_level + 1);
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
//
|
||||
// Created by MightyPork on 2017/11/25.
|
||||
//
|
||||
|
||||
#include "unit_base.h"
|
||||
#include "unit_dac.h"
|
||||
|
||||
#define DAC_INTERNAL
|
||||
#include "_dac_internal.h"
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
enum DacCmd_ {
|
||||
CMD_SET_LEVEL,
|
||||
};
|
||||
|
||||
/** Handle a request message */
|
||||
static error_t UDAC_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command,
|
||||
PayloadParser *pp)
|
||||
{
|
||||
switch (command) {
|
||||
case CMD_SET_LEVEL: {
|
||||
uint16_t ch1 = pp_u16(pp);
|
||||
uint16_t ch2 = pp_u16(pp);
|
||||
uint32_t dual_reg = DAC->DHR12RD;
|
||||
if (ch1 != 0xFFFF) {
|
||||
dual_reg = (dual_reg & 0xFFFF0000) | ch1;
|
||||
}
|
||||
if (ch2 != 0xFFFF) {
|
||||
dual_reg = (dual_reg & 0xFFFF) | (ch2<<16);
|
||||
}
|
||||
DAC->DHR12RD = dual_reg;
|
||||
// Trigger a conversion
|
||||
DAC->SWTRIGR = (DAC_SWTR_CH1 | DAC_SWTR_CH2);
|
||||
return E_SUCCESS;
|
||||
}
|
||||
default:
|
||||
return E_UNKNOWN_COMMAND;
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/** Unit template */
|
||||
const UnitDriver UNIT_DAC = {
|
||||
.name = "DAC",
|
||||
.description = "Analog output",
|
||||
// Settings
|
||||
.preInit = UDAC_preInit,
|
||||
.cfgLoadBinary = UDAC_loadBinary,
|
||||
.cfgWriteBinary = UDAC_writeBinary,
|
||||
.cfgLoadIni = UDAC_loadIni,
|
||||
.cfgWriteIni = UDAC_writeIni,
|
||||
// Init
|
||||
.init = UDAC_init,
|
||||
.deInit = UDAC_deInit,
|
||||
// Function
|
||||
.handleRequest = UDAC_handleRequest,
|
||||
};
|
||||
@@ -0,0 +1,16 @@
|
||||
//
|
||||
// Created by MightyPork on 2017/11/25.
|
||||
//
|
||||
// Digital input unit; single or multiple pin read access on one port (A-F)
|
||||
//
|
||||
|
||||
#ifndef U_DAC_H
|
||||
#define U_DAC_H
|
||||
|
||||
#include "unit.h"
|
||||
|
||||
extern const UnitDriver UNIT_DAC;
|
||||
|
||||
// UU_ prototypes
|
||||
|
||||
#endif //U_DAC_H
|
||||
Reference in New Issue
Block a user