basic static DAC

dac
Ondřej Hruška 7 years ago
parent 590d550a09
commit b2066a9010
Signed by: MightyPork
GPG Key ID: 2C5FD5035250423D
  1. 2
      framework/rsc_enum.h
  2. 1
      gex.mk
  3. 2
      platform/platform.c
  4. 40
      units/dac/_dac_api.c
  5. 99
      units/dac/_dac_init.c
  6. 73
      units/dac/_dac_internal.h
  7. 131
      units/dac/_dac_settings.c
  8. 59
      units/dac/unit_dac.c
  9. 16
      units/dac/unit_dac.h

@ -12,7 +12,7 @@
X(SPI1) X(SPI2) X(SPI3) \ X(SPI1) X(SPI2) X(SPI3) \
X(I2C1) X(I2C2) X(I2C3) \ X(I2C1) X(I2C2) X(I2C3) \
X(ADC1) X(ADC2) X(ADC3) X(ADC4) \ X(ADC1) X(ADC2) X(ADC3) X(ADC4) \
X(DAC1) X(DAC2) \ X(DAC1) \
X(TSC) \ X(TSC) \
X(USART1) X(USART2) X(USART3) X(USART4) X(USART5) X(USART6) \ X(USART1) X(USART2) X(USART3) X(USART4) X(USART5) X(USART6) \
X(TIM1) X(TIM2) X(TIM3) X(TIM4) X(TIM5) \ X(TIM1) X(TIM2) X(TIM3) X(TIM4) X(TIM5) \

@ -18,6 +18,7 @@ GEX_SRC_DIR = \
User/units/fcap \ User/units/fcap \
User/units/touch \ User/units/touch \
User/units/simple_pwm \ User/units/simple_pwm \
User/units/dac \
User/TinyFrame \ User/TinyFrame \
User/CWPack \ User/CWPack \
User/tasks User/tasks

@ -2,6 +2,7 @@
// Created by MightyPork on 2017/11/26. // Created by MightyPork on 2017/11/26.
// //
#include <units/dac/unit_dac.h>
#include "platform.h" #include "platform.h"
#include "usbd_core.h" #include "usbd_core.h"
#include "USB/usb_device.h" #include "USB/usb_device.h"
@ -94,6 +95,7 @@ void plat_init_resources(void)
ureg_add_type(&UNIT_FCAP); ureg_add_type(&UNIT_FCAP);
ureg_add_type(&UNIT_TOUCH); ureg_add_type(&UNIT_TOUCH);
ureg_add_type(&UNIT_PWMDIM); ureg_add_type(&UNIT_PWMDIM);
ureg_add_type(&UNIT_DAC);
// Free all present resources // Free all present resources
{ {

@ -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
Loading…
Cancel
Save