DAC advanced features

dac
Ondřej Hruška 6 years ago
parent b2066a9010
commit 9f40c6e4dd
Signed by: MightyPork
GPG Key ID: 2C5FD5035250423D
  1. 4
      platform/hw_utils.c
  2. 2
      platform/irq_dispatcher.c
  3. 62
      units/dac/_dac_api.c
  4. 392
      units/dac/_dac_core.c
  5. 82
      units/dac/_dac_init.c
  6. 52
      units/dac/_dac_internal.h
  7. 74
      units/dac/_dac_settings.c
  8. 145
      units/dac/unit_dac.c
  9. 1
      units/fcap/_fcap_core.c

@ -263,7 +263,7 @@ void hw_periph_clock_enable(void *periph)
else if (periph == TIM5) __HAL_RCC_TIM5_CLK_ENABLE();
#endif
#ifdef TIM6
else if (periph == TIM6) __HAL_RCC_TIM7_CLK_ENABLE();
else if (periph == TIM6) __HAL_RCC_TIM6_CLK_ENABLE();
#endif
#ifdef TIM7
else if (periph == TIM7) __HAL_RCC_TIM7_CLK_ENABLE();
@ -374,7 +374,7 @@ void hw_periph_clock_disable(void *periph)
else if (periph == TIM5) __HAL_RCC_TIM5_CLK_DISABLE();
#endif
#ifdef TIM6
else if (periph == TIM6) __HAL_RCC_TIM7_CLK_DISABLE();
else if (periph == TIM6) __HAL_RCC_TIM6_CLK_DISABLE();
#endif
#ifdef TIM7
else if (periph == TIM7) __HAL_RCC_TIM7_CLK_DISABLE();

@ -113,7 +113,7 @@ void irqd_init(void)
// NVIC_EnableIRQ(TIM3_IRQn); /*!< TIM3 global Interrupt */
NVIC_EnableIRQ(TIM6_DAC_IRQn); /*!< TIM6 global and DAC channel underrun error Interrupt */
HAL_NVIC_SetPriority(TIM7_IRQn, 2, 0); // Used for DAC timing
HAL_NVIC_SetPriority(TIM6_DAC_IRQn, 2, 0); // Used for DAC timing
NVIC_EnableIRQ(TIM7_IRQn); /*!< TIM7 global Interrupt */
HAL_NVIC_SetPriority(TIM7_IRQn, 2, 0);// this will be for dac (?)

@ -10,31 +10,75 @@
#include "_dac_internal.h"
/**
* Re-configure the
* Re-configure the
* @param unit
*/
void UDAC_Reconfigure(Unit *unit)
{
struct priv *priv = unit->data;
// back-up IT state
bool IT_enabled = (bool) LL_TIM_IsEnabledIT_UPDATE(priv->TIMx);
if (IT_enabled) {
LL_TIM_DisableIT_UPDATE(priv->TIMx);
}
// ...
DAC->CR &= ~(DAC_CR_EN1 | DAC_CR_EN2);
uint32_t CR = 0;
if (priv->cfg.ch1.enable) {
if (priv->cfg.ch[0].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 |
(priv->cfg.ch[0].buffered ? 0 : DAC_CR_BOFF1) |
(priv->ch[0].noise_type << DAC_CR_WAVE1_Pos) |
(priv->ch[0].noise_level & 0xF) << DAC_CR_MAMP1_Pos |
DAC_CR_TEN1 |
(0b111 << DAC_CR_TSEL1_Pos); // software trigger;
CR |= DAC_CR_EN1;
}
if (priv->cfg.ch2.enable) {
if (priv->cfg.ch[1].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 |
(priv->cfg.ch[1].buffered ? 0 : DAC_CR_BOFF2) |
(priv->ch[1].noise_type << DAC_CR_WAVE2_Pos) |
(priv->ch[1].noise_level & 0xF) << DAC_CR_MAMP2_Pos |
DAC_CR_TEN2 |
(0b111 << DAC_CR_TSEL2_Pos); // software trigger
CR |= DAC_CR_EN2;
}
DAC->CR = CR;
// ...
if (IT_enabled) {
LL_TIM_EnableIT_UPDATE(priv->TIMx);
}
}
error_t UDAC_SetFreq(Unit *unit, int channel, float freq)
{
struct priv *priv = unit->data;
priv->ch[channel].increment = (uint32_t) roundf(25.0f * freq * UDAC_VALUE_COUNT * // FIXME constant seems derived from the divide ...?
((float)UDAC_TIM_FREQ_DIVIDER / PLAT_AHB_MHZ)
);
// dbg("Ch %d: Computed increment: %d", channel+1, (int)priv->ch[channel].increment);
return E_SUCCESS;
}
void UDAC_ToggleTimerIfNeeded(Unit *unit)
{
struct priv *priv = unit->data;
if (priv->ch[0].waveform == UDAC_WAVE_DC && priv->ch[1].waveform == UDAC_WAVE_DC) {
LL_TIM_DisableCounter(priv->TIMx);
// manually call the interrupt function to update the level
UDAC_HandleIT(unit);
} else {
LL_TIM_EnableCounter(priv->TIMx);
}
}

@ -0,0 +1,392 @@
//
// Created by MightyPork on 2018/03/10.
//
#include "platform.h"
#include "unit_dac.h"
#define DAC_INTERNAL
#include "_dac_internal.h"
#pragma GCC push_options
#pragma GCC optimize ("O2")
void UDAC_HandleIT(void *arg)
{
Unit *unit = arg;
struct priv *priv = unit->data;
LL_TIM_ClearFlag_UPDATE(priv->TIMx);
// TODO optimize to allow faster update speed
uint16_t vals[2];
for (int i = 0; i < 2; i++) {
struct udac_channel_live *const ch = &priv->ch[i];
if (ch->waveform == UDAC_WAVE_DC) {
// skip the whole counter thing for DC
vals[i] = ch->dc_level;
continue;
}
ch->counter += ch->increment;
const uint16_t index = (uint16_t) (ch->counter >> UDAC_INDEX_SHIFT);
switch (ch->waveform) {
case UDAC_WAVE_SINE: {
const uint32_t phase = index >> (UDAC_INDEX_WIDTH - 2);
uint32_t pos = (uint32_t) index & (((1<<(UDAC_INDEX_WIDTH - 2)) - 1));
if (phase & 0b01) {
// 2nd and 4th quarter (01, 11)
pos = (UDAC_VALUE_COUNT/4 - 1) - pos;
}
uint32_t value;
/* unpack */
const uint32_t nthbyte = (pos * 3) / 2;
const uint8_t topbyte = LUT_sine_8192_quad_packed[nthbyte];
const uint8_t botbyte = LUT_sine_8192_quad_packed[nthbyte + 1];
if (pos & 1) {
// odd index
value = (uint32_t) (((topbyte & 0xF) << 8) | botbyte);
}
else {
value = (uint32_t) ((topbyte << 4) | ((botbyte & 0xF0) >> 4));
}
/* end unpack -> value */
if (phase & 0b10) {
// 3rd and 4th quarter (10, 11)
value = 2047 - value;
}
else {
// 1st and 2nd quarter (00, 01)
value = 2048 + value;
}
vals[i] = (uint16_t) value;
break;
}
case UDAC_WAVE_RECTANGLE:
if (index < ch->rectangle_ontime) {
vals[i] = ch->rectangle_high;
} else {
vals[i] = ch->rectangle_low;
}
break;
case UDAC_WAVE_SAWTOOTH_UP:
vals[i] = (uint16_t) (index / 2); // for 8192 steps, this will produce 0-4095
break;
case UDAC_WAVE_SAWTOOTH_DOWN:
vals[i] = (uint16_t) (4095 - (index / 2)); // for 8192 steps, this will produce 0-4095
break;
case UDAC_WAVE_TRIANGLE: {
if (index < 4096) {
vals[i] = index;
}
else {
vals[i] = (uint16_t) (8191 - index);
}
break;
}
default:
vals[i] = 0; // this shouldn't happen
break;
} // end select waveform
} // end for 0,1
DAC->DHR12RD = (vals[1] << 16) | vals[0];
// Trigger a conversion
DAC->SWTRIGR = (DAC_SWTR_CH1 | DAC_SWTR_CH2);
}
#pragma GCC pop_options
/**
* This is the first 1/4 of a 12-bit sine wave sampled in 8192 points, each two points packed into three bytes (saves 1/4 of space used by uint16_t's)
* The array holds 2048 data points which can be easily offset / flipped to cover the entire waveform.
*
* |<-->|
* _---_
* / \
* / \
* /---------\---------/
* \ /
* \_ _/
* ---
*/
#if 0 // this is rail to rail, but the dac doesn't work well at the rails and it gets flattened
const uint8_t LUT_sine_8192_quad_packed[] = {
0x00, 0x00, 0x02, 0x00, 0x30, 0x05, 0x00, 0x60, 0x08, 0x00, 0x90, 0x0B, 0x00, 0xD0, 0x0E, 0x01, 0x00, 0x11, 0x01, 0x30, 0x14, 0x01, 0x60, 0x18,
0x01, 0x90, 0x1B, 0x01, 0xC0, 0x1E, 0x01, 0xF0, 0x21, 0x02, 0x30, 0x24, 0x02, 0x60, 0x27, 0x02, 0x90, 0x2A, 0x02, 0xC0, 0x2E, 0x02, 0xF0, 0x31,
0x03, 0x20, 0x34, 0x03, 0x50, 0x37, 0x03, 0x90, 0x3A, 0x03, 0xC0, 0x3D, 0x03, 0xF0, 0x40, 0x04, 0x20, 0x43, 0x04, 0x50, 0x47, 0x04, 0x80, 0x4A,
0x04, 0xB0, 0x4D, 0x04, 0xE0, 0x50, 0x05, 0x20, 0x53, 0x05, 0x50, 0x56, 0x05, 0x80, 0x59, 0x05, 0xB0, 0x5D, 0x05, 0xE0, 0x60, 0x06, 0x10, 0x63,
0x06, 0x40, 0x66, 0x06, 0x80, 0x69, 0x06, 0xB0, 0x6C, 0x06, 0xE0, 0x6F, 0x07, 0x10, 0x73, 0x07, 0x40, 0x76, 0x07, 0x70, 0x79, 0x07, 0xA0, 0x7C,
0x07, 0xE0, 0x7F, 0x08, 0x10, 0x82, 0x08, 0x40, 0x85, 0x08, 0x70, 0x88, 0x08, 0xA0, 0x8C, 0x08, 0xD0, 0x8F, 0x09, 0x00, 0x92, 0x09, 0x30, 0x95,
0x09, 0x70, 0x98, 0x09, 0xA0, 0x9B, 0x09, 0xD0, 0x9E, 0x0A, 0x00, 0xA2, 0x0A, 0x30, 0xA5, 0x0A, 0x60, 0xA8, 0x0A, 0x90, 0xAB, 0x0A, 0xC0, 0xAE,
0x0B, 0x00, 0xB1, 0x0B, 0x30, 0xB4, 0x0B, 0x60, 0xB7, 0x0B, 0x90, 0xBB, 0x0B, 0xC0, 0xBE, 0x0B, 0xF0, 0xC1, 0x0C, 0x20, 0xC4, 0x0C, 0x60, 0xC7,
0x0C, 0x90, 0xCA, 0x0C, 0xC0, 0xCD, 0x0C, 0xF0, 0xD0, 0x0D, 0x20, 0xD4, 0x0D, 0x50, 0xD7, 0x0D, 0x80, 0xDA, 0x0D, 0xB0, 0xDD, 0x0D, 0xF0, 0xE0,
0x0E, 0x20, 0xE3, 0x0E, 0x50, 0xE6, 0x0E, 0x80, 0xE9, 0x0E, 0xB0, 0xED, 0x0E, 0xE0, 0xF0, 0x0F, 0x10, 0xF3, 0x0F, 0x40, 0xF6, 0x0F, 0x70, 0xF9,
0x0F, 0xB0, 0xFC, 0x0F, 0xE0, 0xFF, 0x10, 0x11, 0x02, 0x10, 0x41, 0x05, 0x10, 0x71, 0x09, 0x10, 0xA1, 0x0C, 0x10, 0xD1, 0x0F, 0x11, 0x01, 0x12,
0x11, 0x31, 0x15, 0x11, 0x71, 0x18, 0x11, 0xA1, 0x1B, 0x11, 0xD1, 0x1E, 0x12, 0x01, 0x21, 0x12, 0x31, 0x25, 0x12, 0x61, 0x28, 0x12, 0x91, 0x2B,
0x12, 0xC1, 0x2E, 0x12, 0xF1, 0x31, 0x13, 0x31, 0x34, 0x13, 0x61, 0x37, 0x13, 0x91, 0x3A, 0x13, 0xC1, 0x3D, 0x13, 0xF1, 0x41, 0x14, 0x21, 0x44,
0x14, 0x51, 0x47, 0x14, 0x81, 0x4A, 0x14, 0xB1, 0x4D, 0x14, 0xE1, 0x50, 0x15, 0x21, 0x53, 0x15, 0x51, 0x56, 0x15, 0x81, 0x59, 0x15, 0xB1, 0x5C,
0x15, 0xE1, 0x60, 0x16, 0x11, 0x63, 0x16, 0x41, 0x66, 0x16, 0x71, 0x69, 0x16, 0xA1, 0x6C, 0x16, 0xD1, 0x6F, 0x17, 0x11, 0x72, 0x17, 0x41, 0x75,
0x17, 0x71, 0x78, 0x17, 0xA1, 0x7B, 0x17, 0xD1, 0x7E, 0x18, 0x01, 0x81, 0x18, 0x31, 0x85, 0x18, 0x61, 0x88, 0x18, 0x91, 0x8B, 0x18, 0xC1, 0x8E,
0x18, 0xF1, 0x91, 0x19, 0x21, 0x94, 0x19, 0x61, 0x97, 0x19, 0x91, 0x9A, 0x19, 0xC1, 0x9D, 0x19, 0xF1, 0xA0, 0x1A, 0x21, 0xA3, 0x1A, 0x51, 0xA6,
0x1A, 0x81, 0xA9, 0x1A, 0xB1, 0xAD, 0x1A, 0xE1, 0xB0, 0x1B, 0x11, 0xB3, 0x1B, 0x41, 0xB6, 0x1B, 0x71, 0xB9, 0x1B, 0xA1, 0xBC, 0x1B, 0xD1, 0xBF,
0x1C, 0x11, 0xC2, 0x1C, 0x41, 0xC5, 0x1C, 0x71, 0xC8, 0x1C, 0xA1, 0xCB, 0x1C, 0xD1, 0xCE, 0x1D, 0x01, 0xD1, 0x1D, 0x31, 0xD4, 0x1D, 0x61, 0xD7,
0x1D, 0x91, 0xDB, 0x1D, 0xC1, 0xDE, 0x1D, 0xF1, 0xE1, 0x1E, 0x21, 0xE4, 0x1E, 0x51, 0xE7, 0x1E, 0x81, 0xEA, 0x1E, 0xB1, 0xED, 0x1E, 0xE1, 0xF0,
0x1F, 0x11, 0xF3, 0x1F, 0x41, 0xF6, 0x1F, 0x71, 0xF9, 0x1F, 0xB1, 0xFC, 0x1F, 0xE1, 0xFF, 0x20, 0x12, 0x02, 0x20, 0x42, 0x05, 0x20, 0x72, 0x08,
0x20, 0xA2, 0x0B, 0x20, 0xD2, 0x0E, 0x21, 0x02, 0x11, 0x21, 0x32, 0x14, 0x21, 0x62, 0x17, 0x21, 0x92, 0x1A, 0x21, 0xC2, 0x1D, 0x21, 0xF2, 0x20,
0x22, 0x22, 0x23, 0x22, 0x52, 0x26, 0x22, 0x82, 0x2A, 0x22, 0xB2, 0x2D, 0x22, 0xE2, 0x30, 0x23, 0x12, 0x33, 0x23, 0x42, 0x36, 0x23, 0x72, 0x39,
0x23, 0xA2, 0x3C, 0x23, 0xD2, 0x3F, 0x24, 0x02, 0x42, 0x24, 0x32, 0x45, 0x24, 0x62, 0x48, 0x24, 0x92, 0x4B, 0x24, 0xC2, 0x4E, 0x24, 0xF2, 0x51,
0x25, 0x22, 0x54, 0x25, 0x52, 0x57, 0x25, 0x82, 0x5A, 0x25, 0xB2, 0x5D, 0x25, 0xE2, 0x60, 0x26, 0x12, 0x63, 0x26, 0x42, 0x66, 0x26, 0x72, 0x69,
0x26, 0xA2, 0x6C, 0x26, 0xD2, 0x6F, 0x27, 0x02, 0x72, 0x27, 0x32, 0x75, 0x27, 0x62, 0x78, 0x27, 0x92, 0x7B, 0x27, 0xC2, 0x7E, 0x27, 0xF2, 0x81,
0x28, 0x22, 0x84, 0x28, 0x52, 0x87, 0x28, 0x82, 0x8A, 0x28, 0xB2, 0x8D, 0x28, 0xE2, 0x90, 0x29, 0x12, 0x92, 0x29, 0x42, 0x95, 0x29, 0x72, 0x98,
0x29, 0xA2, 0x9B, 0x29, 0xD2, 0x9E, 0x2A, 0x02, 0xA1, 0x2A, 0x32, 0xA4, 0x2A, 0x62, 0xA7, 0x2A, 0x92, 0xAA, 0x2A, 0xC2, 0xAD, 0x2A, 0xF2, 0xB0,
0x2B, 0x22, 0xB3, 0x2B, 0x52, 0xB6, 0x2B, 0x82, 0xB9, 0x2B, 0xA2, 0xBC, 0x2B, 0xD2, 0xBF, 0x2C, 0x02, 0xC2, 0x2C, 0x32, 0xC5, 0x2C, 0x62, 0xC8,
0x2C, 0x92, 0xCB, 0x2C, 0xC2, 0xCE, 0x2C, 0xF2, 0xD1, 0x2D, 0x22, 0xD4, 0x2D, 0x52, 0xD6, 0x2D, 0x82, 0xD9, 0x2D, 0xB2, 0xDC, 0x2D, 0xE2, 0xDF,
0x2E, 0x12, 0xE2, 0x2E, 0x42, 0xE5, 0x2E, 0x72, 0xE8, 0x2E, 0x92, 0xEB, 0x2E, 0xC2, 0xEE, 0x2E, 0xF2, 0xF1, 0x2F, 0x22, 0xF4, 0x2F, 0x52, 0xF7,
0x2F, 0x82, 0xFA, 0x2F, 0xB2, 0xFC, 0x2F, 0xE2, 0xFF, 0x30, 0x13, 0x02, 0x30, 0x43, 0x05, 0x30, 0x73, 0x08, 0x30, 0xA3, 0x0B, 0x30, 0xC3, 0x0E,
0x30, 0xF3, 0x11, 0x31, 0x23, 0x14, 0x31, 0x53, 0x17, 0x31, 0x83, 0x19, 0x31, 0xB3, 0x1C, 0x31, 0xE3, 0x1F, 0x32, 0x13, 0x22, 0x32, 0x43, 0x25,
0x32, 0x73, 0x28, 0x32, 0x93, 0x2B, 0x32, 0xC3, 0x2E, 0x32, 0xF3, 0x31, 0x33, 0x23, 0x33, 0x33, 0x53, 0x36, 0x33, 0x83, 0x39, 0x33, 0xB3, 0x3C,
0x33, 0xE3, 0x3F, 0x34, 0x03, 0x42, 0x34, 0x33, 0x45, 0x34, 0x63, 0x48, 0x34, 0x93, 0x4A, 0x34, 0xC3, 0x4D, 0x34, 0xF3, 0x50, 0x35, 0x23, 0x53,
0x35, 0x43, 0x56, 0x35, 0x73, 0x59, 0x35, 0xA3, 0x5C, 0x35, 0xD3, 0x5E, 0x36, 0x03, 0x61, 0x36, 0x33, 0x64, 0x36, 0x63, 0x67, 0x36, 0x83, 0x6A,
0x36, 0xB3, 0x6D, 0x36, 0xE3, 0x6F, 0x37, 0x13, 0x72, 0x37, 0x43, 0x75, 0x37, 0x73, 0x78, 0x37, 0x93, 0x7B, 0x37, 0xC3, 0x7E, 0x37, 0xF3, 0x80,
0x38, 0x23, 0x83, 0x38, 0x53, 0x86, 0x38, 0x73, 0x89, 0x38, 0xA3, 0x8C, 0x38, 0xD3, 0x8F, 0x39, 0x03, 0x91, 0x39, 0x33, 0x94, 0x39, 0x63, 0x97,
0x39, 0x83, 0x9A, 0x39, 0xB3, 0x9D, 0x39, 0xE3, 0x9F, 0x3A, 0x13, 0xA2, 0x3A, 0x43, 0xA5, 0x3A, 0x63, 0xA8, 0x3A, 0x93, 0xAB, 0x3A, 0xC3, 0xAD,
0x3A, 0xF3, 0xB0, 0x3B, 0x23, 0xB3, 0x3B, 0x43, 0xB6, 0x3B, 0x73, 0xB8, 0x3B, 0xA3, 0xBB, 0x3B, 0xD3, 0xBE, 0x3B, 0xF3, 0xC1, 0x3C, 0x23, 0xC4,
0x3C, 0x53, 0xC6, 0x3C, 0x83, 0xC9, 0x3C, 0xA3, 0xCC, 0x3C, 0xD3, 0xCF, 0x3D, 0x03, 0xD1, 0x3D, 0x33, 0xD4, 0x3D, 0x63, 0xD7, 0x3D, 0x83, 0xDA,
0x3D, 0xB3, 0xDC, 0x3D, 0xE3, 0xDF, 0x3E, 0x13, 0xE2, 0x3E, 0x33, 0xE5, 0x3E, 0x63, 0xE7, 0x3E, 0x93, 0xEA, 0x3E, 0xB3, 0xED, 0x3E, 0xE3, 0xF0,
0x3F, 0x13, 0xF2, 0x3F, 0x43, 0xF5, 0x3F, 0x63, 0xF8, 0x3F, 0x93, 0xFB, 0x3F, 0xC3, 0xFD, 0x3F, 0xF4, 0x00, 0x40, 0x14, 0x03, 0x40, 0x44, 0x05,
0x40, 0x74, 0x08, 0x40, 0x94, 0x0B, 0x40, 0xC4, 0x0E, 0x40, 0xF4, 0x10, 0x41, 0x24, 0x13, 0x41, 0x44, 0x16, 0x41, 0x74, 0x18, 0x41, 0xA4, 0x1B,
0x41, 0xC4, 0x1E, 0x41, 0xF4, 0x20, 0x42, 0x24, 0x23, 0x42, 0x44, 0x26, 0x42, 0x74, 0x28, 0x42, 0xA4, 0x2B, 0x42, 0xC4, 0x2E, 0x42, 0xF4, 0x30,
0x43, 0x24, 0x33, 0x43, 0x54, 0x36, 0x43, 0x74, 0x39, 0x43, 0xA4, 0x3B, 0x43, 0xD4, 0x3E, 0x43, 0xF4, 0x40, 0x44, 0x24, 0x43, 0x44, 0x44, 0x46,
0x44, 0x74, 0x48, 0x44, 0xA4, 0x4B, 0x44, 0xC4, 0x4E, 0x44, 0xF4, 0x50, 0x45, 0x24, 0x53, 0x45, 0x44, 0x56, 0x45, 0x74, 0x58, 0x45, 0xA4, 0x5B,
0x45, 0xC4, 0x5E, 0x45, 0xF4, 0x60, 0x46, 0x24, 0x63, 0x46, 0x44, 0x65, 0x46, 0x74, 0x68, 0x46, 0x94, 0x6B, 0x46, 0xC4, 0x6D, 0x46, 0xF4, 0x70,
0x47, 0x14, 0x73, 0x47, 0x44, 0x75, 0x47, 0x64, 0x78, 0x47, 0x94, 0x7A, 0x47, 0xC4, 0x7D, 0x47, 0xE4, 0x80, 0x48, 0x14, 0x82, 0x48, 0x34, 0x85,
0x48, 0x64, 0x87, 0x48, 0x94, 0x8A, 0x48, 0xB4, 0x8D, 0x48, 0xE4, 0x8F, 0x49, 0x04, 0x92, 0x49, 0x34, 0x94, 0x49, 0x64, 0x97, 0x49, 0x84, 0x99,
0x49, 0xB4, 0x9C, 0x49, 0xD4, 0x9F, 0x4A, 0x04, 0xA1, 0x4A, 0x24, 0xA4, 0x4A, 0x54, 0xA6, 0x4A, 0x74, 0xA9, 0x4A, 0xA4, 0xAB, 0x4A, 0xD4, 0xAE,
0x4A, 0xF4, 0xB0, 0x4B, 0x24, 0xB3, 0x4B, 0x44, 0xB5, 0x4B, 0x74, 0xB8, 0x4B, 0x94, 0xBB, 0x4B, 0xC4, 0xBD, 0x4B, 0xE4, 0xC0, 0x4C, 0x14, 0xC2,
0x4C, 0x34, 0xC5, 0x4C, 0x64, 0xC7, 0x4C, 0x84, 0xCA, 0x4C, 0xB4, 0xCC, 0x4C, 0xD4, 0xCF, 0x4D, 0x04, 0xD1, 0x4D, 0x24, 0xD4, 0x4D, 0x54, 0xD6,
0x4D, 0x74, 0xD9, 0x4D, 0xA4, 0xDB, 0x4D, 0xC4, 0xDE, 0x4D, 0xF4, 0xE0, 0x4E, 0x14, 0xE3, 0x4E, 0x44, 0xE5, 0x4E, 0x64, 0xE8, 0x4E, 0x94, 0xEA,
0x4E, 0xB4, 0xED, 0x4E, 0xE4, 0xEF, 0x4F, 0x04, 0xF2, 0x4F, 0x34, 0xF4, 0x4F, 0x54, 0xF6, 0x4F, 0x84, 0xF9, 0x4F, 0xA4, 0xFB, 0x4F, 0xD4, 0xFE,
0x4F, 0xF5, 0x00, 0x50, 0x25, 0x03, 0x50, 0x45, 0x05, 0x50, 0x65, 0x08, 0x50, 0x95, 0x0A, 0x50, 0xB5, 0x0D, 0x50, 0xE5, 0x0F, 0x51, 0x05, 0x11,
0x51, 0x35, 0x14, 0x51, 0x55, 0x16, 0x51, 0x75, 0x19, 0x51, 0xA5, 0x1B, 0x51, 0xC5, 0x1D, 0x51, 0xF5, 0x20, 0x52, 0x15, 0x22, 0x52, 0x45, 0x25,
0x52, 0x65, 0x27, 0x52, 0x85, 0x2A, 0x52, 0xB5, 0x2C, 0x52, 0xD5, 0x2E, 0x53, 0x05, 0x31, 0x53, 0x25, 0x33, 0x53, 0x45, 0x35, 0x53, 0x75, 0x38,
0x53, 0x95, 0x3A, 0x53, 0xB5, 0x3D, 0x53, 0xE5, 0x3F, 0x54, 0x05, 0x41, 0x54, 0x35, 0x44, 0x54, 0x55, 0x46, 0x54, 0x75, 0x48, 0x54, 0xA5, 0x4B,
0x54, 0xC5, 0x4D, 0x54, 0xE5, 0x4F, 0x55, 0x15, 0x52, 0x55, 0x35, 0x54, 0x55, 0x55, 0x57, 0x55, 0x85, 0x59, 0x55, 0xA5, 0x5B, 0x55, 0xC5, 0x5E,
0x55, 0xF5, 0x60, 0x56, 0x15, 0x62, 0x56, 0x35, 0x64, 0x56, 0x65, 0x67, 0x56, 0x85, 0x69, 0x56, 0xA5, 0x6B, 0x56, 0xD5, 0x6E, 0x56, 0xF5, 0x70,
0x57, 0x15, 0x72, 0x57, 0x35, 0x75, 0x57, 0x65, 0x77, 0x57, 0x85, 0x79, 0x57, 0xA5, 0x7C, 0x57, 0xD5, 0x7E, 0x57, 0xF5, 0x80, 0x58, 0x15, 0x82,
0x58, 0x35, 0x85, 0x58, 0x65, 0x87, 0x58, 0x85, 0x89, 0x58, 0xA5, 0x8B, 0x58, 0xD5, 0x8E, 0x58, 0xF5, 0x90, 0x59, 0x15, 0x92, 0x59, 0x35, 0x94,
0x59, 0x65, 0x97, 0x59, 0x85, 0x99, 0x59, 0xA5, 0x9B, 0x59, 0xC5, 0x9D, 0x59, 0xF5, 0xA0, 0x5A, 0x15, 0xA2, 0x5A, 0x35, 0xA4, 0x5A, 0x55, 0xA6,
0x5A, 0x75, 0xA9, 0x5A, 0xA5, 0xAB, 0x5A, 0xC5, 0xAD, 0x5A, 0xE5, 0xAF, 0x5B, 0x05, 0xB1, 0x5B, 0x35, 0xB4, 0x5B, 0x55, 0xB6, 0x5B, 0x75, 0xB8,
0x5B, 0x95, 0xBA, 0x5B, 0xB5, 0xBC, 0x5B, 0xD5, 0xBF, 0x5C, 0x05, 0xC1, 0x5C, 0x25, 0xC3, 0x5C, 0x45, 0xC5, 0x5C, 0x65, 0xC7, 0x5C, 0x85, 0xC9,
0x5C, 0xB5, 0xCC, 0x5C, 0xD5, 0xCE, 0x5C, 0xF5, 0xD0, 0x5D, 0x15, 0xD2, 0x5D, 0x35, 0xD4, 0x5D, 0x55, 0xD6, 0x5D, 0x75, 0xD9, 0x5D, 0xA5, 0xDB,
0x5D, 0xC5, 0xDD, 0x5D, 0xE5, 0xDF, 0x5E, 0x05, 0xE1, 0x5E, 0x25, 0xE3, 0x5E, 0x45, 0xE5, 0x5E, 0x65, 0xE7, 0x5E, 0x95, 0xEA, 0x5E, 0xB5, 0xEC,
0x5E, 0xD5, 0xEE, 0x5E, 0xF5, 0xF0, 0x5F, 0x15, 0xF2, 0x5F, 0x35, 0xF4, 0x5F, 0x55, 0xF6, 0x5F, 0x75, 0xF8, 0x5F, 0x95, 0xFA, 0x5F, 0xB5, 0xFC,
0x5F, 0xD5, 0xFF, 0x60, 0x06, 0x01, 0x60, 0x26, 0x03, 0x60, 0x46, 0x05, 0x60, 0x66, 0x07, 0x60, 0x86, 0x09, 0x60, 0xA6, 0x0B, 0x60, 0xC6, 0x0D,
0x60, 0xE6, 0x0F, 0x61, 0x06, 0x11, 0x61, 0x26, 0x13, 0x61, 0x46, 0x15, 0x61, 0x66, 0x17, 0x61, 0x86, 0x19, 0x61, 0xA6, 0x1B, 0x61, 0xC6, 0x1D,
0x61, 0xE6, 0x1F, 0x62, 0x06, 0x21, 0x62, 0x26, 0x23, 0x62, 0x46, 0x25, 0x62, 0x66, 0x27, 0x62, 0x86, 0x29, 0x62, 0xA6, 0x2B, 0x62, 0xC6, 0x2D,
0x62, 0xE6, 0x2F, 0x63, 0x06, 0x31, 0x63, 0x26, 0x33, 0x63, 0x46, 0x35, 0x63, 0x66, 0x37, 0x63, 0x86, 0x39, 0x63, 0xA6, 0x3B, 0x63, 0xC6, 0x3D,
0x63, 0xE6, 0x3F, 0x64, 0x06, 0x41, 0x64, 0x26, 0x43, 0x64, 0x46, 0x45, 0x64, 0x66, 0x47, 0x64, 0x86, 0x49, 0x64, 0xA6, 0x4B, 0x64, 0xC6, 0x4D,
0x64, 0xE6, 0x4F, 0x65, 0x06, 0x51, 0x65, 0x26, 0x53, 0x65, 0x46, 0x54, 0x65, 0x56, 0x56, 0x65, 0x76, 0x58, 0x65, 0x96, 0x5A, 0x65, 0xB6, 0x5C,
0x65, 0xD6, 0x5E, 0x65, 0xF6, 0x60, 0x66, 0x16, 0x62, 0x66, 0x36, 0x64, 0x66, 0x56, 0x66, 0x66, 0x76, 0x67, 0x66, 0x86, 0x69, 0x66, 0xA6, 0x6B,
0x66, 0xC6, 0x6D, 0x66, 0xE6, 0x6F, 0x67, 0x06, 0x71, 0x67, 0x26, 0x73, 0x67, 0x46, 0x75, 0x67, 0x56, 0x76, 0x67, 0x76, 0x78, 0x67, 0x96, 0x7A,
0x67, 0xB6, 0x7C, 0x67, 0xD6, 0x7E, 0x67, 0xF6, 0x80, 0x68, 0x16, 0x81, 0x68, 0x26, 0x83, 0x68, 0x46, 0x85, 0x68, 0x66, 0x87, 0x68, 0x86, 0x89,
0x68, 0xA6, 0x8A, 0x68, 0xB6, 0x8C, 0x68, 0xD6, 0x8E, 0x68, 0xF6, 0x90, 0x69, 0x16, 0x92, 0x69, 0x36, 0x93, 0x69, 0x46, 0x95, 0x69, 0x66, 0x97,
0x69, 0x86, 0x99, 0x69, 0xA6, 0x9B, 0x69, 0xB6, 0x9C, 0x69, 0xD6, 0x9E, 0x69, 0xF6, 0xA0, 0x6A, 0x16, 0xA2, 0x6A, 0x36, 0xA3, 0x6A, 0x46, 0xA5,
0x6A, 0x66, 0xA7, 0x6A, 0x86, 0xA9, 0x6A, 0x96, 0xAA, 0x6A, 0xB6, 0xAC, 0x6A, 0xD6, 0xAE, 0x6A, 0xF6, 0xB0, 0x6B, 0x06, 0xB1, 0x6B, 0x26, 0xB3,
0x6B, 0x46, 0xB5, 0x6B, 0x66, 0xB6, 0x6B, 0x76, 0xB8, 0x6B, 0x96, 0xBA, 0x6B, 0xB6, 0xBC, 0x6B, 0xC6, 0xBD, 0x6B, 0xE6, 0xBF, 0x6C, 0x06, 0xC1,
0x6C, 0x16, 0xC2, 0x6C, 0x36, 0xC4, 0x6C, 0x56, 0xC6, 0x6C, 0x66, 0xC7, 0x6C, 0x86, 0xC9, 0x6C, 0xA6, 0xCB, 0x6C, 0xB6, 0xCC, 0x6C, 0xD6, 0xCE,
0x6C, 0xF6, 0xD0, 0x6D, 0x06, 0xD1, 0x6D, 0x26, 0xD3, 0x6D, 0x46, 0xD4, 0x6D, 0x56, 0xD6, 0x6D, 0x76, 0xD8, 0x6D, 0x96, 0xD9, 0x6D, 0xA6, 0xDB,
0x6D, 0xC6, 0xDD, 0x6D, 0xD6, 0xDE, 0x6D, 0xF6, 0xE0, 0x6E, 0x16, 0xE1, 0x6E, 0x26, 0xE3, 0x6E, 0x46, 0xE5, 0x6E, 0x56, 0xE6, 0x6E, 0x76, 0xE8,
0x6E, 0x96, 0xE9, 0x6E, 0xA6, 0xEB, 0x6E, 0xC6, 0xEC, 0x6E, 0xD6, 0xEE, 0x6E, 0xF6, 0xF0, 0x6F, 0x06, 0xF1, 0x6F, 0x26, 0xF3, 0x6F, 0x46, 0xF4,
0x6F, 0x56, 0xF6, 0x6F, 0x76, 0xF7, 0x6F, 0x86, 0xF9, 0x6F, 0xA6, 0xFA, 0x6F, 0xB6, 0xFC, 0x6F, 0xD6, 0xFE, 0x6F, 0xE6, 0xFF, 0x70, 0x07, 0x01,
0x70, 0x17, 0x02, 0x70, 0x37, 0x04, 0x70, 0x47, 0x05, 0x70, 0x67, 0x07, 0x70, 0x77, 0x08, 0x70, 0x97, 0x0A, 0x70, 0xA7, 0x0B, 0x70, 0xC7, 0x0D,
0x70, 0xD7, 0x0E, 0x70, 0xF7, 0x10, 0x71, 0x07, 0x11, 0x71, 0x27, 0x12, 0x71, 0x37, 0x14, 0x71, 0x57, 0x15, 0x71, 0x67, 0x17, 0x71, 0x87, 0x18,
0x71, 0x97, 0x1A, 0x71, 0xA7, 0x1B, 0x71, 0xC7, 0x1D, 0x71, 0xD7, 0x1E, 0x71, 0xF7, 0x1F, 0x72, 0x07, 0x21, 0x72, 0x27, 0x22, 0x72, 0x37, 0x24,
0x72, 0x47, 0x25, 0x72, 0x67, 0x27, 0x72, 0x77, 0x28, 0x72, 0x97, 0x29, 0x72, 0xA7, 0x2B, 0x72, 0xB7, 0x2C, 0x72, 0xD7, 0x2E, 0x72, 0xE7, 0x2F,
0x73, 0x07, 0x30, 0x73, 0x17, 0x32, 0x73, 0x27, 0x33, 0x73, 0x47, 0x34, 0x73, 0x57, 0x36, 0x73, 0x67, 0x37, 0x73, 0x87, 0x38, 0x73, 0x97, 0x3A,
0x73, 0xA7, 0x3B, 0x73, 0xC7, 0x3C, 0x73, 0xD7, 0x3E, 0x73, 0xE7, 0x3F, 0x74, 0x07, 0x40, 0x74, 0x17, 0x42, 0x74, 0x27, 0x43, 0x74, 0x47, 0x44,
0x74, 0x57, 0x46, 0x74, 0x67, 0x47, 0x74, 0x87, 0x48, 0x74, 0x97, 0x4A, 0x74, 0xA7, 0x4B, 0x74, 0xC7, 0x4C, 0x74, 0xD7, 0x4D, 0x74, 0xE7, 0x4F,
0x74, 0xF7, 0x50, 0x75, 0x17, 0x51, 0x75, 0x27, 0x53, 0x75, 0x37, 0x54, 0x75, 0x47, 0x55, 0x75, 0x67, 0x56, 0x75, 0x77, 0x58, 0x75, 0x87, 0x59,
0x75, 0x97, 0x5A, 0x75, 0xB7, 0x5B, 0x75, 0xC7, 0x5D, 0x75, 0xD7, 0x5E, 0x75, 0xE7, 0x5F, 0x76, 0x07, 0x60, 0x76, 0x17, 0x61, 0x76, 0x27, 0x63,
0x76, 0x37, 0x64, 0x76, 0x47, 0x65, 0x76, 0x67, 0x66, 0x76, 0x77, 0x67, 0x76, 0x87, 0x69, 0x76, 0x97, 0x6A, 0x76, 0xA7, 0x6B, 0x76, 0xB7, 0x6C,
0x76, 0xD7, 0x6D, 0x76, 0xE7, 0x6E, 0x76, 0xF7, 0x70, 0x77, 0x07, 0x71, 0x77, 0x17, 0x72, 0x77, 0x27, 0x73, 0x77, 0x47, 0x74, 0x77, 0x57, 0x75,
0x77, 0x67, 0x76, 0x77, 0x77, 0x78, 0x77, 0x87, 0x79, 0x77, 0x97, 0x7A, 0x77, 0xA7, 0x7B, 0x77, 0xB7, 0x7C, 0x77, 0xD7, 0x7D, 0x77, 0xE7, 0x7E,
0x77, 0xF7, 0x7F, 0x78, 0x07, 0x80, 0x78, 0x17, 0x81, 0x78, 0x27, 0x83, 0x78, 0x37, 0x84, 0x78, 0x47, 0x85, 0x78, 0x57, 0x86, 0x78, 0x67, 0x87,
0x78, 0x77, 0x88, 0x78, 0x87, 0x89, 0x78, 0x97, 0x8A, 0x78, 0xA7, 0x8B, 0x78, 0xC7, 0x8C, 0x78, 0xD7, 0x8D, 0x78, 0xE7, 0x8E, 0x78, 0xF7, 0x8F,
0x79, 0x07, 0x90, 0x79, 0x17, 0x91, 0x79, 0x27, 0x92, 0x79, 0x37, 0x93, 0x79, 0x47, 0x94, 0x79, 0x57, 0x95, 0x79, 0x67, 0x96, 0x79, 0x77, 0x97,
0x79, 0x87, 0x98, 0x79, 0x97, 0x99, 0x79, 0xA7, 0x9A, 0x79, 0xB7, 0x9B, 0x79, 0xC7, 0x9C, 0x79, 0xD7, 0x9D, 0x79, 0xE7, 0x9E, 0x79, 0xE7, 0x9F,
0x79, 0xF7, 0xA0, 0x7A, 0x07, 0xA1, 0x7A, 0x17, 0xA2, 0x7A, 0x27, 0xA3, 0x7A, 0x37, 0xA4, 0x7A, 0x47, 0xA5, 0x7A, 0x57, 0xA5, 0x7A, 0x67, 0xA6,
0x7A, 0x77, 0xA7, 0x7A, 0x87, 0xA8, 0x7A, 0x97, 0xA9, 0x7A, 0xA7, 0xAA, 0x7A, 0xA7, 0xAB, 0x7A, 0xB7, 0xAC, 0x7A, 0xC7, 0xAD, 0x7A, 0xD7, 0xAE,
0x7A, 0xE7, 0xAE, 0x7A, 0xF7, 0xAF, 0x7B, 0x07, 0xB0, 0x7B, 0x17, 0xB1, 0x7B, 0x17, 0xB2, 0x7B, 0x27, 0xB3, 0x7B, 0x37, 0xB4, 0x7B, 0x47, 0xB4,
0x7B, 0x57, 0xB5, 0x7B, 0x67, 0xB6, 0x7B, 0x77, 0xB7, 0x7B, 0x77, 0xB8, 0x7B, 0x87, 0xB9, 0x7B, 0x97, 0xB9, 0x7B, 0xA7, 0xBA, 0x7B, 0xB7, 0xBB,
0x7B, 0xB7, 0xBC, 0x7B, 0xC7, 0xBD, 0x7B, 0xD7, 0xBD, 0x7B, 0xE7, 0xBE, 0x7B, 0xF7, 0xBF, 0x7B, 0xF7, 0xC0, 0x7C, 0x07, 0xC1, 0x7C, 0x17, 0xC1,
0x7C, 0x27, 0xC2, 0x7C, 0x27, 0xC3, 0x7C, 0x37, 0xC4, 0x7C, 0x47, 0xC4, 0x7C, 0x57, 0xC5, 0x7C, 0x57, 0xC6, 0x7C, 0x67, 0xC7, 0x7C, 0x77, 0xC7,
0x7C, 0x87, 0xC8, 0x7C, 0x87, 0xC9, 0x7C, 0x97, 0xC9, 0x7C, 0xA7, 0xCA, 0x7C, 0xA7, 0xCB, 0x7C, 0xB7, 0xCC, 0x7C, 0xC7, 0xCC, 0x7C, 0xD7, 0xCD,
0x7C, 0xD7, 0xCE, 0x7C, 0xE7, 0xCE, 0x7C, 0xF7, 0xCF, 0x7C, 0xF7, 0xD0, 0x7D, 0x07, 0xD0, 0x7D, 0x17, 0xD1, 0x7D, 0x17, 0xD2, 0x7D, 0x27, 0xD2,
0x7D, 0x37, 0xD3, 0x7D, 0x37, 0xD4, 0x7D, 0x47, 0xD4, 0x7D, 0x57, 0xD5, 0x7D, 0x57, 0xD5, 0x7D, 0x67, 0xD6, 0x7D, 0x67, 0xD7, 0x7D, 0x77, 0xD7,
0x7D, 0x87, 0xD8, 0x7D, 0x87, 0xD9, 0x7D, 0x97, 0xD9, 0x7D, 0x97, 0xDA, 0x7D, 0xA7, 0xDA, 0x7D, 0xB7, 0xDB, 0x7D, 0xB7, 0xDC, 0x7D, 0xC7, 0xDC,
0x7D, 0xC7, 0xDD, 0x7D, 0xD7, 0xDD, 0x7D, 0xE7, 0xDE, 0x7D, 0xE7, 0xDE, 0x7D, 0xF7, 0xDF, 0x7D, 0xF7, 0xE0, 0x7E, 0x07, 0xE0, 0x7E, 0x07, 0xE1,
0x7E, 0x17, 0xE1, 0x7E, 0x17, 0xE2, 0x7E, 0x27, 0xE2, 0x7E, 0x27, 0xE3, 0x7E, 0x37, 0xE3, 0x7E, 0x37, 0xE4, 0x7E, 0x47, 0xE4, 0x7E, 0x57, 0xE5,
0x7E, 0x57, 0xE5, 0x7E, 0x67, 0xE6, 0x7E, 0x67, 0xE6, 0x7E, 0x67, 0xE7, 0x7E, 0x77, 0xE7, 0x7E, 0x77, 0xE8, 0x7E, 0x87, 0xE8, 0x7E, 0x87, 0xE9,
0x7E, 0x97, 0xE9, 0x7E, 0x97, 0xEA, 0x7E, 0xA7, 0xEA, 0x7E, 0xA7, 0xEA, 0x7E, 0xB7, 0xEB, 0x7E, 0xB7, 0xEB, 0x7E, 0xC7, 0xEC, 0x7E, 0xC7, 0xEC,
0x7E, 0xC7, 0xED, 0x7E, 0xD7, 0xED, 0x7E, 0xD7, 0xED, 0x7E, 0xE7, 0xEE, 0x7E, 0xE7, 0xEE, 0x7E, 0xE7, 0xEF, 0x7E, 0xF7, 0xEF, 0x7E, 0xF7, 0xEF,
0x7F, 0x07, 0xF0, 0x7F, 0x07, 0xF0, 0x7F, 0x07, 0xF1, 0x7F, 0x17, 0xF1, 0x7F, 0x17, 0xF1, 0x7F, 0x17, 0xF2, 0x7F, 0x27, 0xF2, 0x7F, 0x27, 0xF2,
0x7F, 0x37, 0xF3, 0x7F, 0x37, 0xF3, 0x7F, 0x37, 0xF3, 0x7F, 0x47, 0xF4, 0x7F, 0x47, 0xF4, 0x7F, 0x47, 0xF4, 0x7F, 0x57, 0xF5, 0x7F, 0x57, 0xF5,
0x7F, 0x57, 0xF5, 0x7F, 0x57, 0xF6, 0x7F, 0x67, 0xF6, 0x7F, 0x67, 0xF6, 0x7F, 0x67, 0xF6, 0x7F, 0x77, 0xF7, 0x7F, 0x77, 0xF7, 0x7F, 0x77, 0xF7,
0x7F, 0x77, 0xF8, 0x7F, 0x87, 0xF8, 0x7F, 0x87, 0xF8, 0x7F, 0x87, 0xF8, 0x7F, 0x87, 0xF9, 0x7F, 0x97, 0xF9, 0x7F, 0x97, 0xF9, 0x7F, 0x97, 0xF9,
0x7F, 0x97, 0xFA, 0x7F, 0xA7, 0xFA, 0x7F, 0xA7, 0xFA, 0x7F, 0xA7, 0xFA, 0x7F, 0xA7, 0xFA, 0x7F, 0xB7, 0xFB, 0x7F, 0xB7, 0xFB, 0x7F, 0xB7, 0xFB,
0x7F, 0xB7, 0xFB, 0x7F, 0xB7, 0xFB, 0x7F, 0xC7, 0xFC, 0x7F, 0xC7, 0xFC, 0x7F, 0xC7, 0xFC, 0x7F, 0xC7, 0xFC, 0x7F, 0xC7, 0xFC, 0x7F, 0xC7, 0xFC,
0x7F, 0xD7, 0xFD, 0x7F, 0xD7, 0xFD, 0x7F, 0xD7, 0xFD, 0x7F, 0xD7, 0xFD, 0x7F, 0xD7, 0xFD, 0x7F, 0xD7, 0xFD, 0x7F, 0xD7, 0xFD, 0x7F, 0xD7, 0xFE,
0x7F, 0xE7, 0xFE, 0x7F, 0xE7, 0xFE, 0x7F, 0xE7, 0xFE, 0x7F, 0xE7, 0xFE, 0x7F, 0xE7, 0xFE, 0x7F, 0xE7, 0xFE, 0x7F, 0xE7, 0xFE, 0x7F, 0xE7, 0xFE,
0x7F, 0xE7, 0xFE, 0x7F, 0xE7, 0xFE, 0x7F, 0xF7, 0xFF, 0x7F, 0xF7, 0xFF, 0x7F, 0xF7, 0xFF, 0x7F, 0xF7, 0xFF, 0x7F, 0xF7, 0xFF, 0x7F, 0xF7, 0xFF,
0x7F, 0xF7, 0xFF, 0x7F, 0xF7, 0xFF, 0x7F, 0xF7, 0xFF, 0x7F, 0xF7, 0xFF, 0x7F, 0xF7, 0xFF, 0x7F, 0xF7, 0xFF, 0x7F, 0xF7, 0xFF, 0x7F, 0xF7, 0xFF,
};
#else
// range 2000
const uint8_t LUT_sine_8192_quad_packed[3072] = {
0x00, 0x00, 0x02, 0x00, 0x30, 0x05, 0x00, 0x60, 0x08, 0x00, 0x90, 0x0B, 0x00, 0xC0, 0x0E, 0x00, 0xF0, 0x11, 0x01, 0x20, 0x14, 0x01, 0x50, 0x17,
0x01, 0x90, 0x1A, 0x01, 0xC0, 0x1D, 0x01, 0xF0, 0x20, 0x02, 0x20, 0x23, 0x02, 0x50, 0x26, 0x02, 0x80, 0x29, 0x02, 0xB0, 0x2C, 0x02, 0xE0, 0x30,
0x03, 0x10, 0x33, 0x03, 0x40, 0x36, 0x03, 0x70, 0x39, 0x03, 0xA0, 0x3C, 0x03, 0xD0, 0x3F, 0x04, 0x00, 0x42, 0x04, 0x30, 0x45, 0x04, 0x70, 0x48,
0x04, 0xA0, 0x4B, 0x04, 0xD0, 0x4E, 0x05, 0x00, 0x51, 0x05, 0x30, 0x54, 0x05, 0x60, 0x57, 0x05, 0x90, 0x5A, 0x05, 0xC0, 0x5E, 0x05, 0xF0, 0x61,
0x06, 0x20, 0x64, 0x06, 0x50, 0x67, 0x06, 0x80, 0x6A, 0x06, 0xB0, 0x6D, 0x06, 0xE0, 0x70, 0x07, 0x10, 0x73, 0x07, 0x50, 0x76, 0x07, 0x80, 0x79,
0x07, 0xB0, 0x7C, 0x07, 0xE0, 0x7F, 0x08, 0x10, 0x82, 0x08, 0x40, 0x85, 0x08, 0x70, 0x88, 0x08, 0xA0, 0x8B, 0x08, 0xD0, 0x8F, 0x09, 0x00, 0x92,
0x09, 0x30, 0x95, 0x09, 0x60, 0x98, 0x09, 0x90, 0x9B, 0x09, 0xC0, 0x9E, 0x09, 0xF0, 0xA1, 0x0A, 0x20, 0xA4, 0x0A, 0x50, 0xA7, 0x0A, 0x90, 0xAA,
0x0A, 0xC0, 0xAD, 0x0A, 0xF0, 0xB0, 0x0B, 0x20, 0xB3, 0x0B, 0x50, 0xB6, 0x0B, 0x80, 0xB9, 0x0B, 0xB0, 0xBC, 0x0B, 0xE0, 0xBF, 0x0C, 0x10, 0xC3,
0x0C, 0x40, 0xC6, 0x0C, 0x70, 0xC9, 0x0C, 0xA0, 0xCC, 0x0C, 0xD0, 0xCF, 0x0D, 0x00, 0xD2, 0x0D, 0x30, 0xD5, 0x0D, 0x60, 0xD8, 0x0D, 0x90, 0xDB,
0x0D, 0xC0, 0xDE, 0x0D, 0xF0, 0xE1, 0x0E, 0x30, 0xE4, 0x0E, 0x60, 0xE7, 0x0E, 0x90, 0xEA, 0x0E, 0xC0, 0xED, 0x0E, 0xF0, 0xF0, 0x0F, 0x20, 0xF3,
0x0F, 0x50, 0xF6, 0x0F, 0x80, 0xF9, 0x0F, 0xB0, 0xFC, 0x0F, 0xE0, 0xFF, 0x10, 0x11, 0x03, 0x10, 0x41, 0x06, 0x10, 0x71, 0x09, 0x10, 0xA1, 0x0C,
0x10, 0xD1, 0x0F, 0x11, 0x01, 0x12, 0x11, 0x31, 0x15, 0x11, 0x61, 0x18, 0x11, 0x91, 0x1B, 0x11, 0xC1, 0x1E, 0x11, 0xF1, 0x21, 0x12, 0x21, 0x24,
0x12, 0x51, 0x27, 0x12, 0x81, 0x2A, 0x12, 0xC1, 0x2D, 0x12, 0xF1, 0x30, 0x13, 0x21, 0x33, 0x13, 0x51, 0x36, 0x13, 0x81, 0x39, 0x13, 0xB1, 0x3C,
0x13, 0xE1, 0x3F, 0x14, 0x11, 0x42, 0x14, 0x41, 0x45, 0x14, 0x71, 0x48, 0x14, 0xA1, 0x4B, 0x14, 0xD1, 0x4E, 0x15, 0x01, 0x51, 0x15, 0x31, 0x54,
0x15, 0x61, 0x57, 0x15, 0x91, 0x5A, 0x15, 0xC1, 0x5D, 0x15, 0xF1, 0x60, 0x16, 0x21, 0x64, 0x16, 0x51, 0x67, 0x16, 0x81, 0x6A, 0x16, 0xB1, 0x6D,
0x16, 0xE1, 0x70, 0x17, 0x11, 0x73, 0x17, 0x41, 0x76, 0x17, 0x71, 0x79, 0x17, 0xA1, 0x7C, 0x17, 0xD1, 0x7F, 0x18, 0x01, 0x82, 0x18, 0x31, 0x85,
0x18, 0x61, 0x88, 0x18, 0x91, 0x8B, 0x18, 0xC1, 0x8E, 0x18, 0xF1, 0x91, 0x19, 0x21, 0x94, 0x19, 0x51, 0x97, 0x19, 0x81, 0x9A, 0x19, 0xB1, 0x9D,
0x19, 0xE1, 0xA0, 0x1A, 0x11, 0xA3, 0x1A, 0x41, 0xA6, 0x1A, 0x71, 0xA9, 0x1A, 0xA1, 0xAC, 0x1A, 0xD1, 0xAF, 0x1B, 0x01, 0xB2, 0x1B, 0x31, 0xB5,
0x1B, 0x61, 0xB8, 0x1B, 0x91, 0xBB, 0x1B, 0xC1, 0xBE, 0x1B, 0xF1, 0xC1, 0x1C, 0x21, 0xC4, 0x1C, 0x51, 0xC7, 0x1C, 0x81, 0xCA, 0x1C, 0xB1, 0xCD,
0x1C, 0xE1, 0xD0, 0x1D, 0x11, 0xD3, 0x1D, 0x41, 0xD6, 0x1D, 0x71, 0xD9, 0x1D, 0xA1, 0xDC, 0x1D, 0xD1, 0xDF, 0x1E, 0x01, 0xE1, 0x1E, 0x31, 0xE4,
0x1E, 0x61, 0xE7, 0x1E, 0x91, 0xEA, 0x1E, 0xC1, 0xED, 0x1E, 0xF1, 0xF0, 0x1F, 0x21, 0xF3, 0x1F, 0x51, 0xF6, 0x1F, 0x81, 0xF9, 0x1F, 0xB1, 0xFC,
0x1F, 0xE1, 0xFF, 0x20, 0x12, 0x02, 0x20, 0x42, 0x05, 0x20, 0x72, 0x08, 0x20, 0xA2, 0x0B, 0x20, 0xD2, 0x0E, 0x21, 0x02, 0x11, 0x21, 0x22, 0x14,
0x21, 0x52, 0x17, 0x21, 0x82, 0x1A, 0x21, 0xB2, 0x1D, 0x21, 0xE2, 0x20, 0x22, 0x12, 0x23, 0x22, 0x42, 0x26, 0x22, 0x72, 0x29, 0x22, 0xA2, 0x2C,
0x22, 0xD2, 0x2F, 0x23, 0x02, 0x31, 0x23, 0x32, 0x34, 0x23, 0x62, 0x37, 0x23, 0x92, 0x3A, 0x23, 0xC2, 0x3D, 0x23, 0xF2, 0x40, 0x24, 0x22, 0x43,
0x24, 0x52, 0x46, 0x24, 0x82, 0x49, 0x24, 0xA2, 0x4C, 0x24, 0xD2, 0x4F, 0x25, 0x02, 0x52, 0x25, 0x32, 0x55, 0x25, 0x62, 0x58, 0x25, 0x92, 0x5B,
0x25, 0xC2, 0x5D, 0x25, 0xF2, 0x60, 0x26, 0x22, 0x63, 0x26, 0x52, 0x66, 0x26, 0x82, 0x69, 0x26, 0xB2, 0x6C, 0x26, 0xE2, 0x6F, 0x27, 0x02, 0x72,
0x27, 0x32, 0x75, 0x27, 0x62, 0x78, 0x27, 0x92, 0x7B, 0x27, 0xC2, 0x7E, 0x27, 0xF2, 0x80, 0x28, 0x22, 0x83, 0x28, 0x52, 0x86, 0x28, 0x82, 0x89,
0x28, 0xB2, 0x8C, 0x28, 0xE2, 0x8F, 0x29, 0x02, 0x92, 0x29, 0x32, 0x95, 0x29, 0x62, 0x98, 0x29, 0x92, 0x9B, 0x29, 0xC2, 0x9D, 0x29, 0xF2, 0xA0,
0x2A, 0x22, 0xA3, 0x2A, 0x52, 0xA6, 0x2A, 0x82, 0xA9, 0x2A, 0xA2, 0xAC, 0x2A, 0xD2, 0xAF, 0x2B, 0x02, 0xB2, 0x2B, 0x32, 0xB5, 0x2B, 0x62, 0xB7,
0x2B, 0x92, 0xBA, 0x2B, 0xC2, 0xBD, 0x2B, 0xF2, 0xC0, 0x2C, 0x12, 0xC3, 0x2C, 0x42, 0xC6, 0x2C, 0x72, 0xC9, 0x2C, 0xA2, 0xCB, 0x2C, 0xD2, 0xCE,
0x2D, 0x02, 0xD1, 0x2D, 0x32, 0xD4, 0x2D, 0x62, 0xD7, 0x2D, 0x82, 0xDA, 0x2D, 0xB2, 0xDD, 0x2D, 0xE2, 0xE0, 0x2E, 0x12, 0xE2, 0x2E, 0x42, 0xE5,
0x2E, 0x72, 0xE8, 0x2E, 0x92, 0xEB, 0x2E, 0xC2, 0xEE, 0x2E, 0xF2, 0xF1, 0x2F, 0x22, 0xF3, 0x2F, 0x52, 0xF6, 0x2F, 0x82, 0xF9, 0x2F, 0xB2, 0xFC,
0x2F, 0xD2, 0xFF, 0x30, 0x03, 0x02, 0x30, 0x33, 0x04, 0x30, 0x63, 0x07, 0x30, 0x93, 0x0A, 0x30, 0xC3, 0x0D, 0x30, 0xE3, 0x10, 0x31, 0x13, 0x13,
0x31, 0x43, 0x15, 0x31, 0x73, 0x18, 0x31, 0xA3, 0x1B, 0x31, 0xC3, 0x1E, 0x31, 0xF3, 0x21, 0x32, 0x23, 0x23, 0x32, 0x53, 0x26, 0x32, 0x83, 0x29,
0x32, 0xA3, 0x2C, 0x32, 0xD3, 0x2F, 0x33, 0x03, 0x31, 0x33, 0x33, 0x34, 0x33, 0x63, 0x37, 0x33, 0x83, 0x3A, 0x33, 0xB3, 0x3D, 0x33, 0xE3, 0x3F,
0x34, 0x13, 0x42, 0x34, 0x43, 0x45, 0x34, 0x63, 0x48, 0x34, 0x93, 0x4B, 0x34, 0xC3, 0x4D, 0x34, 0xF3, 0x50, 0x35, 0x23, 0x53, 0x35, 0x43, 0x56,
0x35, 0x73, 0x58, 0x35, 0xA3, 0x5B, 0x35, 0xD3, 0x5E, 0x35, 0xF3, 0x61, 0x36, 0x23, 0x64, 0x36, 0x53, 0x66, 0x36, 0x83, 0x69, 0x36, 0xA3, 0x6C,
0x36, 0xD3, 0x6F, 0x37, 0x03, 0x71, 0x37, 0x33, 0x74, 0x37, 0x53, 0x77, 0x37, 0x83, 0x7A, 0x37, 0xB3, 0x7C, 0x37, 0xE3, 0x7F, 0x38, 0x03, 0x82,
0x38, 0x33, 0x85, 0x38, 0x63, 0x87, 0x38, 0x93, 0x8A, 0x38, 0xB3, 0x8D, 0x38, 0xE3, 0x90, 0x39, 0x13, 0x92, 0x39, 0x43, 0x95, 0x39, 0x63, 0x98,
0x39, 0x93, 0x9A, 0x39, 0xC3, 0x9D, 0x39, 0xF3, 0xA0, 0x3A, 0x13, 0xA3, 0x3A, 0x43, 0xA5, 0x3A, 0x73, 0xA8, 0x3A, 0x93, 0xAB, 0x3A, 0xC3, 0xAD,
0x3A, 0xF3, 0xB0, 0x3B, 0x13, 0xB3, 0x3B, 0x43, 0xB6, 0x3B, 0x73, 0xB8, 0x3B, 0xA3, 0xBB, 0x3B, 0xC3, 0xBE, 0x3B, 0xF3, 0xC0, 0x3C, 0x23, 0xC3,
0x3C, 0x43, 0xC6, 0x3C, 0x73, 0xC8, 0x3C, 0xA3, 0xCB, 0x3C, 0xC3, 0xCE, 0x3C, 0xF3, 0xD0, 0x3D, 0x23, 0xD3, 0x3D, 0x43, 0xD6, 0x3D, 0x73, 0xD8,
0x3D, 0xA3, 0xDB, 0x3D, 0xC3, 0xDE, 0x3D, 0xF3, 0xE0, 0x3E, 0x23, 0xE3, 0x3E, 0x43, 0xE6, 0x3E, 0x73, 0xE8, 0x3E, 0xA3, 0xEB, 0x3E, 0xC3, 0xEE,
0x3E, 0xF3, 0xF0, 0x3F, 0x23, 0xF3, 0x3F, 0x43, 0xF6, 0x3F, 0x73, 0xF8, 0x3F, 0xA3, 0xFB, 0x3F, 0xC3, 0xFE, 0x3F, 0xF4, 0x00, 0x40, 0x24, 0x03,
0x40, 0x44, 0x06, 0x40, 0x74, 0x08, 0x40, 0x94, 0x0B, 0x40, 0xC4, 0x0D, 0x40, 0xF4, 0x10, 0x41, 0x14, 0x13, 0x41, 0x44, 0x15, 0x41, 0x74, 0x18,
0x41, 0x94, 0x1A, 0x41, 0xC4, 0x1D, 0x41, 0xE4, 0x20, 0x42, 0x14, 0x22, 0x42, 0x44, 0x25, 0x42, 0x64, 0x28, 0x42, 0x94, 0x2A, 0x42, 0xB4, 0x2D,
0x42, 0xE4, 0x2F, 0x43, 0x14, 0x32, 0x43, 0x34, 0x34, 0x43, 0x64, 0x37, 0x43, 0x84, 0x3A, 0x43, 0xB4, 0x3C, 0x43, 0xE4, 0x3F, 0x44, 0x04, 0x41,
0x44, 0x34, 0x44, 0x44, 0x54, 0x47, 0x44, 0x84, 0x49, 0x44, 0xA4, 0x4C, 0x44, 0xD4, 0x4E, 0x44, 0xF4, 0x51, 0x45, 0x24, 0x53, 0x45, 0x54, 0x56,
0x45, 0x74, 0x58, 0x45, 0xA4, 0x5B, 0x45, 0xC4, 0x5E, 0x45, 0xF4, 0x60, 0x46, 0x14, 0x63, 0x46, 0x44, 0x65, 0x46, 0x64, 0x68, 0x46, 0x94, 0x6A,
0x46, 0xB4, 0x6D, 0x46, 0xE4, 0x6F, 0x47, 0x14, 0x72, 0x47, 0x34, 0x74, 0x47, 0x64, 0x77, 0x47, 0x84, 0x79, 0x47, 0xB4, 0x7C, 0x47, 0xD4, 0x7E,
0x48, 0x04, 0x81, 0x48, 0x24, 0x83, 0x48, 0x54, 0x86, 0x48, 0x74, 0x88, 0x48, 0xA4, 0x8B, 0x48, 0xC4, 0x8D, 0x48, 0xF4, 0x90, 0x49, 0x14, 0x92,
0x49, 0x44, 0x95, 0x49, 0x64, 0x97, 0x49, 0x94, 0x9A, 0x49, 0xB4, 0x9C, 0x49, 0xE4, 0x9F, 0x4A, 0x04, 0xA1, 0x4A, 0x24, 0xA4, 0x4A, 0x54, 0xA6,
0x4A, 0x74, 0xA9, 0x4A, 0xA4, 0xAB, 0x4A, 0xC4, 0xAE, 0x4A, 0xF4, 0xB0, 0x4B, 0x14, 0xB2, 0x4B, 0x44, 0xB5, 0x4B, 0x64, 0xB7, 0x4B, 0x94, 0xBA,
0x4B, 0xB4, 0xBC, 0x4B, 0xD4, 0xBF, 0x4C, 0x04, 0xC1, 0x4C, 0x24, 0xC4, 0x4C, 0x54, 0xC6, 0x4C, 0x74, 0xC8, 0x4C, 0xA4, 0xCB, 0x4C, 0xC4, 0xCD,
0x4C, 0xE4, 0xD0, 0x4D, 0x14, 0xD2, 0x4D, 0x34, 0xD5, 0x4D, 0x64, 0xD7, 0x4D, 0x84, 0xD9, 0x4D, 0xB4, 0xDC, 0x4D, 0xD4, 0xDE, 0x4D, 0xF4, 0xE1,
0x4E, 0x24, 0xE3, 0x4E, 0x44, 0xE5, 0x4E, 0x74, 0xE8, 0x4E, 0x94, 0xEA, 0x4E, 0xB4, 0xEC, 0x4E, 0xE4, 0xEF, 0x4F, 0x04, 0xF1, 0x4F, 0x24, 0xF4,
0x4F, 0x54, 0xF6, 0x4F, 0x74, 0xF8, 0x4F, 0xA4, 0xFB, 0x4F, 0xC4, 0xFD, 0x4F, 0xE4, 0xFF, 0x50, 0x15, 0x02, 0x50, 0x35, 0x04, 0x50, 0x55, 0x06,
0x50, 0x85, 0x09, 0x50, 0xA5, 0x0B, 0x50, 0xC5, 0x0E, 0x50, 0xF5, 0x10, 0x51, 0x15, 0x12, 0x51, 0x35, 0x15, 0x51, 0x65, 0x17, 0x51, 0x85, 0x19,
0x51, 0xA5, 0x1C, 0x51, 0xD5, 0x1E, 0x51, 0xF5, 0x20, 0x52, 0x15, 0x22, 0x52, 0x45, 0x25, 0x52, 0x65, 0x27, 0x52, 0x85, 0x29, 0x52, 0xB5, 0x2C,
0x52, 0xD5, 0x2E, 0x52, 0xF5, 0x30, 0x53, 0x15, 0x33, 0x53, 0x45, 0x35, 0x53, 0x65, 0x37, 0x53, 0x85, 0x39, 0x53, 0xB5, 0x3C, 0x53, 0xD5, 0x3E,
0x53, 0xF5, 0x40, 0x54, 0x15, 0x43, 0x54, 0x45, 0x45, 0x54, 0x65, 0x47, 0x54, 0x85, 0x49, 0x54, 0xA5, 0x4C, 0x54, 0xD5, 0x4E, 0x54, 0xF5, 0x50,
0x55, 0x15, 0x52, 0x55, 0x35, 0x55, 0x55, 0x65, 0x57, 0x55, 0x85, 0x59, 0x55, 0xA5, 0x5B, 0x55, 0xC5, 0x5E, 0x55, 0xF5, 0x60, 0x56, 0x15, 0x62,
0x56, 0x35, 0x64, 0x56, 0x55, 0x66, 0x56, 0x85, 0x69, 0x56, 0xA5, 0x6B, 0x56, 0xC5, 0x6D, 0x56, 0xE5, 0x6F, 0x57, 0x05, 0x71, 0x57, 0x35, 0x74,
0x57, 0x55, 0x76, 0x57, 0x75, 0x78, 0x57, 0x95, 0x7A, 0x57, 0xB5, 0x7C, 0x57, 0xE5, 0x7F, 0x58, 0x05, 0x81, 0x58, 0x25, 0x83, 0x58, 0x45, 0x85,
0x58, 0x65, 0x87, 0x58, 0x85, 0x89, 0x58, 0xB5, 0x8C, 0x58, 0xD5, 0x8E, 0x58, 0xF5, 0x90, 0x59, 0x15, 0x92, 0x59, 0x35, 0x94, 0x59, 0x55, 0x96,
0x59, 0x75, 0x99, 0x59, 0xA5, 0x9B, 0x59, 0xC5, 0x9D, 0x59, 0xE5, 0x9F, 0x5A, 0x05, 0xA1, 0x5A, 0x25, 0xA3, 0x5A, 0x45, 0xA5, 0x5A, 0x65, 0xA7,
0x5A, 0x85, 0xAA, 0x5A, 0xB5, 0xAC, 0x5A, 0xD5, 0xAE, 0x5A, 0xF5, 0xB0, 0x5B, 0x15, 0xB2, 0x5B, 0x35, 0xB4, 0x5B, 0x55, 0xB6, 0x5B, 0x75, 0xB8,
0x5B, 0x95, 0xBA, 0x5B, 0xB5, 0xBC, 0x5B, 0xD5, 0xBF, 0x5C, 0x05, 0xC1, 0x5C, 0x25, 0xC3, 0x5C, 0x45, 0xC5, 0x5C, 0x65, 0xC7, 0x5C, 0x85, 0xC9,
0x5C, 0xA5, 0xCB, 0x5C, 0xC5, 0xCD, 0x5C, 0xE5, 0xCF, 0x5D, 0x05, 0xD1, 0x5D, 0x25, 0xD3, 0x5D, 0x45, 0xD5, 0x5D, 0x65, 0xD7, 0x5D, 0x85, 0xD9,
0x5D, 0xA5, 0xDB, 0x5D, 0xC5, 0xDD, 0x5D, 0xE5, 0xDF, 0x5E, 0x05, 0xE1, 0x5E, 0x25, 0xE3, 0x5E, 0x45, 0xE5, 0x5E, 0x65, 0xE7, 0x5E, 0x85, 0xE9,
0x5E, 0xA5, 0xEB, 0x5E, 0xC5, 0xED, 0x5E, 0xE5, 0xEF, 0x5F, 0x05, 0xF1, 0x5F, 0x25, 0xF3, 0x5F, 0x45, 0xF5, 0x5F, 0x65, 0xF7, 0x5F, 0x85, 0xF9,
0x5F, 0xA5, 0xFB, 0x5F, 0xC5, 0xFD, 0x5F, 0xE5, 0xFF, 0x60, 0x06, 0x01, 0x60, 0x26, 0x03, 0x60, 0x46, 0x05, 0x60, 0x66, 0x07, 0x60, 0x86, 0x09,
0x60, 0xA6, 0x0B, 0x60, 0xC6, 0x0D, 0x60, 0xE6, 0x0F, 0x61, 0x06, 0x11, 0x61, 0x26, 0x13, 0x61, 0x46, 0x15, 0x61, 0x66, 0x17, 0x61, 0x86, 0x19,
0x61, 0x96, 0x1A, 0x61, 0xB6, 0x1C, 0x61, 0xD6, 0x1E, 0x61, 0xF6, 0x20, 0x62, 0x16, 0x22, 0x62, 0x36, 0x24, 0x62, 0x56, 0x26, 0x62, 0x76, 0x28,
0x62, 0x96, 0x2A, 0x62, 0xB6, 0x2C, 0x62, 0xC6, 0x2D, 0x62, 0xE6, 0x2F, 0x63, 0x06, 0x31, 0x63, 0x26, 0x33, 0x63, 0x46, 0x35, 0x63, 0x66, 0x37,
0x63, 0x86, 0x39, 0x63, 0xA6, 0x3A, 0x63, 0xB6, 0x3C, 0x63, 0xD6, 0x3E, 0x63, 0xF6, 0x40, 0x64, 0x16, 0x42, 0x64, 0x36, 0x44, 0x64, 0x56, 0x46,
0x64, 0x66, 0x47, 0x64, 0x86, 0x49, 0x64, 0xA6, 0x4B, 0x64, 0xC6, 0x4D, 0x64, 0xE6, 0x4F, 0x65, 0x06, 0x50, 0x65, 0x16, 0x52, 0x65, 0x36, 0x54,
0x65, 0x56, 0x56, 0x65, 0x76, 0x58, 0x65, 0x96, 0x59, 0x65, 0xA6, 0x5B, 0x65, 0xC6, 0x5D, 0x65, 0xE6, 0x5F, 0x66, 0x06, 0x61, 0x66, 0x16, 0x62,
0x66, 0x36, 0x64, 0x66, 0x56, 0x66, 0x66, 0x76, 0x68, 0x66, 0x86, 0x69, 0x66, 0xA6, 0x6B, 0x66, 0xC6, 0x6D, 0x66, 0xE6, 0x6F, 0x66, 0xF6, 0x70,
0x67, 0x16, 0x72, 0x67, 0x36, 0x74, 0x67, 0x56, 0x76, 0x67, 0x66, 0x77, 0x67, 0x86, 0x79, 0x67, 0xA6, 0x7B, 0x67, 0xC6, 0x7C, 0x67, 0xD6, 0x7E,
0x67, 0xF6, 0x80, 0x68, 0x16, 0x81, 0x68, 0x26, 0x83, 0x68, 0x46, 0x85, 0x68, 0x66, 0x87, 0x68, 0x76, 0x88, 0x68, 0x96, 0x8A, 0x68, 0xB6, 0x8C,
0x68, 0xC6, 0x8D, 0x68, 0xE6, 0x8F, 0x69, 0x06, 0x91, 0x69, 0x16, 0x92, 0x69, 0x36, 0x94, 0x69, 0x56, 0x96, 0x69, 0x66, 0x97, 0x69, 0x86, 0x99,
0x69, 0xA6, 0x9B, 0x69, 0xB6, 0x9C, 0x69, 0xD6, 0x9E, 0x69, 0xF6, 0x9F, 0x6A, 0x06, 0xA1, 0x6A, 0x26, 0xA3, 0x6A, 0x36, 0xA4, 0x6A, 0x56, 0xA6,
0x6A, 0x76, 0xA8, 0x6A, 0x86, 0xA9, 0x6A, 0xA6, 0xAB, 0x6A, 0xC6, 0xAC, 0x6A, 0xD6, 0xAE, 0x6A, 0xF6, 0xB0, 0x6B, 0x06, 0xB1, 0x6B, 0x26, 0xB3,
0x6B, 0x36, 0xB4, 0x6B, 0x56, 0xB6, 0x6B, 0x76, 0xB7, 0x6B, 0x86, 0xB9, 0x6B, 0xA6, 0xBB, 0x6B, 0xB6, 0xBC, 0x6B, 0xD6, 0xBE, 0x6B, 0xE6, 0xBF,
0x6C, 0x06, 0xC1, 0x6C, 0x16, 0xC2, 0x6C, 0x36, 0xC4, 0x6C, 0x56, 0xC5, 0x6C, 0x66, 0xC7, 0x6C, 0x86, 0xC8, 0x6C, 0x96, 0xCA, 0x6C, 0xB6, 0xCB,
0x6C, 0xC6, 0xCD, 0x6C, 0xE6, 0xCE, 0x6C, 0xF6, 0xD0, 0x6D, 0x16, 0xD1, 0x6D, 0x26, 0xD3, 0x6D, 0x46, 0xD4, 0x6D, 0x56, 0xD6, 0x6D, 0x76, 0xD7,
0x6D, 0x86, 0xD9, 0x6D, 0xA6, 0xDA, 0x6D, 0xB6, 0xDC, 0x6D, 0xD6, 0xDD, 0x6D, 0xE6, 0xDF, 0x6D, 0xF6, 0xE0, 0x6E, 0x16, 0xE2, 0x6E, 0x26, 0xE3,
0x6E, 0x46, 0xE5, 0x6E, 0x56, 0xE6, 0x6E, 0x76, 0xE7, 0x6E, 0x86, 0xE9, 0x6E, 0xA6, 0xEA, 0x6E, 0xB6, 0xEC, 0x6E, 0xC6, 0xED, 0x6E, 0xE6, 0xEF,
0x6E, 0xF6, 0xF0, 0x6F, 0x16, 0xF1, 0x6F, 0x26, 0xF3, 0x6F, 0x36, 0xF4, 0x6F, 0x56, 0xF6, 0x6F, 0x66, 0xF7, 0x6F, 0x86, 0xF8, 0x6F, 0x96, 0xFA,
0x6F, 0xA6, 0xFB, 0x6F, 0xC6, 0xFD, 0x6F, 0xD6, 0xFE, 0x6F, 0xF6, 0xFF, 0x70, 0x07, 0x01, 0x70, 0x17, 0x02, 0x70, 0x37, 0x03, 0x70, 0x47, 0x05,
0x70, 0x57, 0x06, 0x70, 0x77, 0x07, 0x70, 0x87, 0x09, 0x70, 0x97, 0x0A, 0x70, 0xB7, 0x0B, 0x70, 0xC7, 0x0D, 0x70, 0xD7, 0x0E, 0x70, 0xF7, 0x0F,
0x71, 0x07, 0x11, 0x71, 0x17, 0x12, 0x71, 0x37, 0x13, 0x71, 0x47, 0x15, 0x71, 0x57, 0x16, 0x71, 0x67, 0x17, 0x71, 0x87, 0x18, 0x71, 0x97, 0x1A,
0x71, 0xA7, 0x1B, 0x71, 0xC7, 0x1C, 0x71, 0xD7, 0x1E, 0x71, 0xE7, 0x1F, 0x71, 0xF7, 0x20, 0x72, 0x17, 0x21, 0x72, 0x27, 0x23, 0x72, 0x37, 0x24,
0x72, 0x47, 0x25, 0x72, 0x67, 0x26, 0x72, 0x77, 0x28, 0x72, 0x87, 0x29, 0x72, 0x97, 0x2A, 0x72, 0xB7, 0x2B, 0x72, 0xC7, 0x2C, 0x72, 0xD7, 0x2E,
0x72, 0xE7, 0x2F, 0x72, 0xF7, 0x30, 0x73, 0x17, 0x31, 0x73, 0x27, 0x32, 0x73, 0x37, 0x34, 0x73, 0x47, 0x35, 0x73, 0x57, 0x36, 0x73, 0x77, 0x37,
0x73, 0x87, 0x38, 0x73, 0x97, 0x3A, 0x73, 0xA7, 0x3B, 0x73, 0xB7, 0x3C, 0x73, 0xC7, 0x3D, 0x73, 0xE7, 0x3E, 0x73, 0xF7, 0x3F, 0x74, 0x07, 0x40,
0x74, 0x17, 0x42, 0x74, 0x27, 0x43, 0x74, 0x37, 0x44, 0x74, 0x47, 0x45, 0x74, 0x67, 0x46, 0x74, 0x77, 0x47, 0x74, 0x87, 0x48, 0x74, 0x97, 0x49,
0x74, 0xA7, 0x4B, 0x74, 0xB7, 0x4C, 0x74, 0xC7, 0x4D, 0x74, 0xD7, 0x4E, 0x74, 0xE7, 0x4F, 0x74, 0xF7, 0x50, 0x75, 0x17, 0x51, 0x75, 0x27, 0x52,
0x75, 0x37, 0x53, 0x75, 0x47, 0x54, 0x75, 0x57, 0x55, 0x75, 0x67, 0x56, 0x75, 0x77, 0x57, 0x75, 0x87, 0x58, 0x75, 0x97, 0x5A, 0x75, 0xA7, 0x5B,
0x75, 0xB7, 0x5C, 0x75, 0xC7, 0x5D, 0x75, 0xD7, 0x5E, 0x75, 0xE7, 0x5F, 0x75, 0xF7, 0x60, 0x76, 0x07, 0x61, 0x76, 0x17, 0x62, 0x76, 0x27, 0x63,
0x76, 0x37, 0x64, 0x76, 0x47, 0x65, 0x76, 0x57, 0x66, 0x76, 0x67, 0x67, 0x76, 0x77, 0x68, 0x76, 0x87, 0x69, 0x76, 0x97, 0x6A, 0x76, 0xA7, 0x6B,
0x76, 0xB7, 0x6C, 0x76, 0xC7, 0x6C, 0x76, 0xD7, 0x6D, 0x76, 0xE7, 0x6E, 0x76, 0xF7, 0x6F, 0x77, 0x07, 0x70, 0x77, 0x17, 0x71, 0x77, 0x27, 0x72,
0x77, 0x37, 0x73, 0x77, 0x47, 0x74, 0x77, 0x47, 0x75, 0x77, 0x57, 0x76, 0x77, 0x67, 0x77, 0x77, 0x77, 0x78, 0x77, 0x87, 0x79, 0x77, 0x97, 0x79,
0x77, 0xA7, 0x7A, 0x77, 0xB7, 0x7B, 0x77, 0xC7, 0x7C, 0x77, 0xD7, 0x7D, 0x77, 0xD7, 0x7E, 0x77, 0xE7, 0x7F, 0x77, 0xF7, 0x80, 0x78, 0x07, 0x80,
0x78, 0x17, 0x81, 0x78, 0x27, 0x82, 0x78, 0x37, 0x83, 0x78, 0x37, 0x84, 0x78, 0x47, 0x85, 0x78, 0x57, 0x85, 0x78, 0x67, 0x86, 0x78, 0x77, 0x87,
0x78, 0x87, 0x88, 0x78, 0x87, 0x89, 0x78, 0x97, 0x8A, 0x78, 0xA7, 0x8A, 0x78, 0xB7, 0x8B, 0x78, 0xC7, 0x8C, 0x78, 0xC7, 0x8D, 0x78, 0xD7, 0x8E,
0x78, 0xE7, 0x8E, 0x78, 0xF7, 0x8F, 0x79, 0x07, 0x90, 0x79, 0x07, 0x91, 0x79, 0x17, 0x91, 0x79, 0x27, 0x92, 0x79, 0x37, 0x93, 0x79, 0x37, 0x94,
0x79, 0x47, 0x94, 0x79, 0x57, 0x95, 0x79, 0x67, 0x96, 0x79, 0x67, 0x97, 0x79, 0x77, 0x97, 0x79, 0x87, 0x98, 0x79, 0x87, 0x99, 0x79, 0x97, 0x9A,
0x79, 0xA7, 0x9A, 0x79, 0xB7, 0x9B, 0x79, 0xB7, 0x9C, 0x79, 0xC7, 0x9C, 0x79, 0xD7, 0x9D, 0x79, 0xD7, 0x9E, 0x79, 0xE7, 0x9E, 0x79, 0xF7, 0x9F,
0x79, 0xF7, 0xA0, 0x7A, 0x07, 0xA0, 0x7A, 0x17, 0xA1, 0x7A, 0x17, 0xA2, 0x7A, 0x27, 0xA2, 0x7A, 0x37, 0xA3, 0x7A, 0x37, 0xA4, 0x7A, 0x47, 0xA4,
0x7A, 0x57, 0xA5, 0x7A, 0x57, 0xA6, 0x7A, 0x67, 0xA6, 0x7A, 0x77, 0xA7, 0x7A, 0x77, 0xA7, 0x7A, 0x87, 0xA8, 0x7A, 0x87, 0xA9, 0x7A, 0x97, 0xA9,
0x7A, 0xA7, 0xAA, 0x7A, 0xA7, 0xAA, 0x7A, 0xB7, 0xAB, 0x7A, 0xB7, 0xAC, 0x7A, 0xC7, 0xAC, 0x7A, 0xD7, 0xAD, 0x7A, 0xD7, 0xAD, 0x7A, 0xE7, 0xAE,
0x7A, 0xE7, 0xAE, 0x7A, 0xF7, 0xAF, 0x7A, 0xF7, 0xB0, 0x7B, 0x07, 0xB0, 0x7B, 0x07, 0xB1, 0x7B, 0x17, 0xB1, 0x7B, 0x17, 0xB2, 0x7B, 0x27, 0xB2,
0x7B, 0x37, 0xB3, 0x7B, 0x37, 0xB3, 0x7B, 0x47, 0xB4, 0x7B, 0x47, 0xB4, 0x7B, 0x57, 0xB5, 0x7B, 0x57, 0xB5, 0x7B, 0x67, 0xB6, 0x7B, 0x67, 0xB6,
0x7B, 0x77, 0xB7, 0x7B, 0x77, 0xB7, 0x7B, 0x87, 0xB8, 0x7B, 0x87, 0xB8, 0x7B, 0x97, 0xB9, 0x7B, 0x97, 0xB9, 0x7B, 0x97, 0xBA, 0x7B, 0xA7, 0xBA,
0x7B, 0xA7, 0xBB, 0x7B, 0xB7, 0xBB, 0x7B, 0xB7, 0xBB, 0x7B, 0xC7, 0xBC, 0x7B, 0xC7, 0xBC, 0x7B, 0xD7, 0xBD, 0x7B, 0xD7, 0xBD, 0x7B, 0xD7, 0xBE,
0x7B, 0xE7, 0xBE, 0x7B, 0xE7, 0xBE, 0x7B, 0xF7, 0xBF, 0x7B, 0xF7, 0xBF, 0x7B, 0xF7, 0xC0, 0x7C, 0x07, 0xC0, 0x7C, 0x07, 0xC0, 0x7C, 0x17, 0xC1,
0x7C, 0x17, 0xC1, 0x7C, 0x17, 0xC2, 0x7C, 0x27, 0xC2, 0x7C, 0x27, 0xC2, 0x7C, 0x27, 0xC3, 0x7C, 0x37, 0xC3, 0x7C, 0x37, 0xC3, 0x7C, 0x37, 0xC4,
0x7C, 0x47, 0xC4, 0x7C, 0x47, 0xC4, 0x7C, 0x47, 0xC5, 0x7C, 0x57, 0xC5, 0x7C, 0x57, 0xC5, 0x7C, 0x57, 0xC6, 0x7C, 0x67, 0xC6, 0x7C, 0x67, 0xC6,
0x7C, 0x67, 0xC7, 0x7C, 0x77, 0xC7, 0x7C, 0x77, 0xC7, 0x7C, 0x77, 0xC7, 0x7C, 0x87, 0xC8, 0x7C, 0x87, 0xC8, 0x7C, 0x87, 0xC8, 0x7C, 0x87, 0xC8,
0x7C, 0x97, 0xC9, 0x7C, 0x97, 0xC9, 0x7C, 0x97, 0xC9, 0x7C, 0x97, 0xCA, 0x7C, 0xA7, 0xCA, 0x7C, 0xA7, 0xCA, 0x7C, 0xA7, 0xCA, 0x7C, 0xA7, 0xCA,
0x7C, 0xB7, 0xCB, 0x7C, 0xB7, 0xCB, 0x7C, 0xB7, 0xCB, 0x7C, 0xB7, 0xCB, 0x7C, 0xB7, 0xCC, 0x7C, 0xC7, 0xCC, 0x7C, 0xC7, 0xCC, 0x7C, 0xC7, 0xCC,
0x7C, 0xC7, 0xCC, 0x7C, 0xC7, 0xCD, 0x7C, 0xD7, 0xCD, 0x7C, 0xD7, 0xCD, 0x7C, 0xD7, 0xCD, 0x7C, 0xD7, 0xCD, 0x7C, 0xD7, 0xCD, 0x7C, 0xD7, 0xCE,
0x7C, 0xE7, 0xCE, 0x7C, 0xE7, 0xCE, 0x7C, 0xE7, 0xCE, 0x7C, 0xE7, 0xCE, 0x7C, 0xE7, 0xCE, 0x7C, 0xE7, 0xCE, 0x7C, 0xE7, 0xCE, 0x7C, 0xF7, 0xCF,
0x7C, 0xF7, 0xCF, 0x7C, 0xF7, 0xCF, 0x7C, 0xF7, 0xCF, 0x7C, 0xF7, 0xCF, 0x7C, 0xF7, 0xCF, 0x7C, 0xF7, 0xCF, 0x7C, 0xF7, 0xCF, 0x7C, 0xF7, 0xCF,
0x7C, 0xF7, 0xCF, 0x7C, 0xF7, 0xD0, 0x7D, 0x07, 0xD0, 0x7D, 0x07, 0xD0, 0x7D, 0x07, 0xD0, 0x7D, 0x07, 0xD0, 0x7D, 0x07, 0xD0, 0x7D, 0x07, 0xD0,
0x7D, 0x07, 0xD0, 0x7D, 0x07, 0xD0, 0x7D, 0x07, 0xD0, 0x7D, 0x07, 0xD0, 0x7D, 0x07, 0xD0, 0x7D, 0x07, 0xD0, 0x7D, 0x07, 0xD0, 0x7D, 0x07, 0xD0,
};
#endif

@ -14,21 +14,26 @@ 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;
for (int i = 0; i < 2; i++) {
priv->cfg.ch[i].buffered = true;
priv->cfg.ch[i].enable = true;
priv->cfg.ch[i].noise_level = 2;
priv->cfg.ch[i].noise_type = NOISE_NONE;
priv->ch[i].waveform = UDAC_WAVE_DC;
priv->ch[i].dc_level = 2047;
priv->ch[i].rectangle_ontime = 4096; // half
priv->ch[i].rectangle_high = 4095;
priv->ch[i].rectangle_low = 0;
priv->ch[i].counter = 0;
priv->ch[i].increment = 0; // stopped
priv->ch[i].phase = 0;
}
priv->ch2.noise_type = priv->cfg.ch2.noise_type;
priv->ch2.noise_level = priv->cfg.ch2.noise_level;
UDAC_SetFreq(unit, 0, 1000);
UDAC_SetFreq(unit, 1, 1000);
return E_SUCCESS;
}
@ -39,13 +44,22 @@ error_t UDAC_init(Unit *unit)
bool suc = true;
struct priv *priv = unit->data;
// copy noise config
priv->ch[0].noise_type = priv->cfg.ch[0].noise_type;
priv->ch[0].noise_level = priv->cfg.ch[0].noise_level;
priv->ch[1].noise_type = priv->cfg.ch[1].noise_type;
priv->ch[1].noise_level = priv->cfg.ch[1].noise_level;
// 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;
TRY(rsc_claim(unit, R_TIM6));
priv->TIMx = TIM6;
const bool e1 = priv->cfg.ch[0].enable;
const bool e2 = priv->cfg.ch[1].enable;
if (e1) {
TRY(rsc_claim(unit, r_ch1));
@ -62,6 +76,7 @@ error_t UDAC_init(Unit *unit)
__HAL_RCC_DAC1_RELEASE_RESET();
hw_periph_clock_enable(DAC1);
hw_periph_clock_enable(priv->TIMx);
GPIO_TypeDef *port;
uint32_t ll;
@ -74,7 +89,35 @@ error_t UDAC_init(Unit *unit)
LL_GPIO_SetPinMode(port, ll, LL_GPIO_MODE_ANALOG);
}
UDAC_Reconfigure(unit);
uint16_t presc = 1;
// presets... TODO pick the highest useable one (or find a new one)
#if UDAC_TIM_FREQ_DIVIDER == 1
uint32_t count = PLAT_AHB_MHZ;
#elif UDAC_TIM_FREQ_DIVIDER == 2
uint32_t count = PLAT_AHB_MHZ * 2;
#elif UDAC_TIM_FREQ_DIVIDER == 4
uint32_t count = PLAT_AHB_MHZ * 4;
#elif UDAC_TIM_FREQ_DIVIDER == 8
uint32_t count = PLAT_AHB_MHZ * 8;
#else
#error "bad freq"
#endif
// dbg("Presc %d, count %d", (int)presc, (int)count);
LL_TIM_SetPrescaler(priv->TIMx, (uint32_t) (presc - 1));
LL_TIM_SetAutoReload(priv->TIMx, count - 1);
LL_TIM_EnableARRPreload(priv->TIMx);
LL_TIM_GenerateEvent_UPDATE(priv->TIMx);
irqd_attach(priv->TIMx, UDAC_HandleIT, unit);
LL_TIM_EnableIT_UPDATE(priv->TIMx);
UDAC_Reconfigure(unit); // works with the timer - it should be inited already
// do not enbale counter initially - no need
// LL_TIM_EnableCounter(priv->TIMx);
return E_SUCCESS;
}
@ -88,7 +131,12 @@ void UDAC_deInit(Unit *unit)
// de-init peripherals
if (unit->status == E_SUCCESS ) {
LL_DAC_DeInit(DAC);
LL_TIM_DisableCounter(priv->TIMx);
hw_periph_clock_disable(DAC1);
hw_periph_clock_disable(priv->TIMx);
irqd_detach(priv->TIMx, UDAC_HandleIT);
}
// Release all resources, deinit pins

@ -12,9 +12,18 @@
#include "unit_base.h"
enum UDAC_Noise {
NOISE_NONE = 0b00,
NOISE_WHITE = 0b01,
NOISE_TRIANGLE = 0b10,
NOISE_NONE = 0b00, // 0
NOISE_WHITE = 0b01, // 1
NOISE_TRIANGLE = 0b10, // 2
};
enum UDAC_Waveform {
UDAC_WAVE_DC,
UDAC_WAVE_SINE,
UDAC_WAVE_TRIANGLE,
UDAC_WAVE_SAWTOOTH_UP,
UDAC_WAVE_SAWTOOTH_DOWN,
UDAC_WAVE_RECTANGLE,
};
struct udac_channel_cfg {
@ -24,22 +33,45 @@ struct udac_channel_cfg {
uint8_t noise_level; // 0-11
};
// 0 - 1 MHz, 2-500k, 4-250k, 8-125k
#define UDAC_TIM_FREQ_DIVIDER 8
#define UDAC_INDEX_WIDTH 13 // corresponds to 8192 places
#define UDAC_INDEX_SHIFT (32 - UDAC_INDEX_WIDTH)
#define UDAC_MAX_INDEX ((1 << UDAC_INDEX_WIDTH) - 1)
#define UDAC_VALUE_COUNT (1 << UDAC_INDEX_WIDTH)
extern const uint8_t LUT_sine_8192_quad_packed[];
struct udac_channel_live {
enum UDAC_Noise noise_type;
uint8_t noise_level; // 0-11
enum UDAC_Waveform waveform;
uint16_t rectangle_ontime; // for rectangle wave, 0-8191
uint16_t rectangle_high;
uint16_t rectangle_low;
uint16_t dc_level; // for DC wave
uint32_t counter;
uint32_t increment;
// last set phase if the frequencies are the same
// - can be used for live frequency changes without reset (meaningful only with matching increment values)
uint16_t phase;
uint16_t last_index;
uint16_t last_value;
};
/** Private data structure */
struct priv {
// settings
struct {
struct udac_channel_cfg ch1;
struct udac_channel_cfg ch2;
struct udac_channel_cfg ch[2];
} cfg;
// internal state
struct udac_channel_live ch1;
struct udac_channel_live ch2;
struct udac_channel_live ch[2];
TIM_TypeDef *TIMx; // timer used for the DDS function
};
@ -70,4 +102,10 @@ void UDAC_deInit(Unit *unit);
void UDAC_Reconfigure(Unit *unit);
void UDAC_HandleIT(void *arg);
error_t UDAC_SetFreq(Unit *unit, int channel, float freq);
void UDAC_ToggleTimerIfNeeded(Unit *unit);
#endif //GEX_F072_DAC_INTERNAL_H

@ -16,15 +16,15 @@ void UDAC_loadBinary(Unit *unit, PayloadParser *pp)
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);
priv->cfg.ch[0].enable = pp_bool(pp);
priv->cfg.ch[0].buffered = pp_bool(pp);
priv->cfg.ch[0].noise_type = (enum UDAC_Noise) pp_u8(pp);
priv->cfg.ch[0].noise_level = pp_u8(pp);
priv->cfg.ch[1].enable = pp_bool(pp);
priv->cfg.ch[1].buffered = pp_bool(pp);
priv->cfg.ch[1].noise_type = (enum UDAC_Noise) pp_u8(pp);
priv->cfg.ch[1].noise_level = pp_u8(pp);
}
/** Write to a binary buffer for storing in Flash */
@ -34,15 +34,15 @@ void UDAC_writeBinary(Unit *unit, PayloadBuilder *pb)
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.ch[0].enable);
pb_bool(pb, priv->cfg.ch[0].buffered);
pb_u8(pb, priv->cfg.ch[0].noise_type);
pb_u8(pb, priv->cfg.ch[0].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);
pb_bool(pb, priv->cfg.ch[1].enable);
pb_bool(pb, priv->cfg.ch[1].buffered);
pb_u8(pb, priv->cfg.ch[1].noise_type);
pb_u8(pb, priv->cfg.ch[1].noise_level);
}
// ------------------------------------------------------------------------
@ -55,13 +55,13 @@ error_t UDAC_loadIni(Unit *unit, const char *key, const char *value)
// Ch1
if (streq(key, "ch1_enable")) {
priv->cfg.ch1.enable = cfg_bool_parse(value, &suc);
priv->cfg.ch[0].enable = cfg_bool_parse(value, &suc);
}
else if (streq(key, "ch1_buff")) {
priv->cfg.ch1.buffered = cfg_bool_parse(value, &suc);
priv->cfg.ch[0].buffered = cfg_bool_parse(value, &suc);
}
else if (streq(key, "ch1_noise")) {
priv->cfg.ch1.noise_type =
priv->cfg.ch[0].noise_type =
(enum UDAC_Noise) cfg_enum3_parse(value,
"NONE", NOISE_NONE,
"WHITE", NOISE_WHITE,
@ -71,17 +71,17 @@ error_t UDAC_loadIni(Unit *unit, const char *key, const char *value)
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);
priv->cfg.ch[0].noise_level = (uint8_t) (x - 1);
}
// Ch2
else if (streq(key, "ch2_enable")) {
priv->cfg.ch2.enable = cfg_bool_parse(value, &suc);
priv->cfg.ch[1].enable = cfg_bool_parse(value, &suc);
}
else if (streq(key, "ch2_buff")) {
priv->cfg.ch2.buffered = cfg_bool_parse(value, &suc);
priv->cfg.ch[1].buffered = cfg_bool_parse(value, &suc);
}
else if (streq(key, "ch2_noise")) {
priv->cfg.ch2.noise_type =
priv->cfg.ch[1].noise_type =
(enum UDAC_Noise) cfg_enum3_parse(value,
"NONE", NOISE_NONE,
"WHITE", NOISE_WHITE,
@ -91,7 +91,7 @@ error_t UDAC_loadIni(Unit *unit, const char *key, const char *value)
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);
priv->cfg.ch[1].noise_level = (uint8_t) (x - 1);
}
// end
else {
@ -108,24 +108,24 @@ 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_entry_s(iw, "ch1_enable", str_yn(priv->cfg.ch[0].enable));
iw_entry_s(iw, "ch2_enable", str_yn(priv->cfg.ch[1].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, "Enable output buffer");
iw_entry_s(iw, "ch1_buff", str_yn(priv->cfg.ch[0].buffered));
iw_entry_s(iw, "ch2_buff", str_yn(priv->cfg.ch[1].buffered));
iw_comment(iw, "Superimposed noise type (NONE,WHITE,TRIANGLE)");
iw_entry_s(iw, "ch1_noise", cfg_enum3_encode(priv->cfg.ch1.noise_type,
iw_comment(iw, "Superimposed noise type (NONE,WHITE,TRIANGLE) and nbr. of bits (1-12)");
iw_entry_s(iw, "ch1_noise", cfg_enum3_encode(priv->cfg.ch[0].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,
iw_entry_d(iw, "ch1_noise-level", priv->cfg.ch[0].noise_level + 1);
iw_entry_s(iw, "ch2_noise", cfg_enum3_encode(priv->cfg.ch[1].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);
iw_entry_d(iw, "ch2_noise-level", priv->cfg.ch[1].noise_level + 1);
}

@ -10,33 +10,140 @@
// ------------------------------------------------------------------------
// Works OK up to about 20 kHz, could work faster with a faster interrupt
// (may be possible with some optimizations / adjusting priorities...)
enum DacCmd_ {
CMD_SET_LEVEL,
CMD_WAVE_DC = 0,
CMD_WAVE_SINE = 1,
CMD_WAVE_TRIANGLE = 2,
CMD_WAVE_SAWTOOTH_UP = 3,
CMD_WAVE_SAWTOOTH_DOWN = 4,
CMD_WAVE_RECTANGLE = 5,
CMD_SYNC = 10,
CMD_SET_FREQUENCY = 20,
CMD_SET_PHASE = 21,
CMD_SET_DITHER = 22,
};
/** Handle a request message */
static error_t UDAC_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command,
PayloadParser *pp)
static error_t UDAC_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, PayloadParser *pp)
{
struct priv *priv = unit->data;
// Exceptions that aren't per-channel
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);
case CMD_SYNC:
dbg("Sync");
priv->ch[0].counter = priv->ch[0].phase << UDAC_INDEX_SHIFT;
priv->ch[1].counter = priv->ch[1].phase << UDAC_INDEX_SHIFT;
return E_SUCCESS;
}
uint8_t channels = pp_u8(pp);
bool want_reinit = false;
bool want_tog_timer = false;
// TODO move this stuff to the api file
for (int i = 0; i < 2; i++) {
if (channels & (1<<i)) {
switch (command) {
case CMD_SET_FREQUENCY:;
float freq = pp_float(pp);
TRY(UDAC_SetFreq(unit, i, freq));
break;
case CMD_WAVE_DC:
priv->ch[i].dc_level = pp_u16(pp);
priv->ch[i].waveform = UDAC_WAVE_DC;
want_tog_timer = true;
break;
case CMD_WAVE_SINE:
priv->ch[i].waveform = UDAC_WAVE_SINE;
want_tog_timer = true;
break;
case CMD_WAVE_TRIANGLE:
priv->ch[i].waveform = UDAC_WAVE_TRIANGLE;
want_tog_timer = true;
break;
case CMD_WAVE_SAWTOOTH_UP:
priv->ch[i].waveform = UDAC_WAVE_SAWTOOTH_UP;
want_tog_timer = true;
break;
case CMD_WAVE_SAWTOOTH_DOWN:
priv->ch[i].waveform = UDAC_WAVE_SAWTOOTH_DOWN;
want_tog_timer = true;
break;
case CMD_WAVE_RECTANGLE:;
uint16_t ontime = pp_u16(pp);
uint16_t high = pp_u16(pp);
uint16_t low = pp_u16(pp);
// use 0xFFFF to skip setting the value
if (high < 4096) priv->ch[i].rectangle_high = high;
if (low < 4096) priv->ch[i].rectangle_low = low;
if (ontime <= UDAC_VALUE_COUNT) priv->ch[i].rectangle_ontime = ontime;
// dbg("Set rect hi %d, low %d", (int)priv->ch[i].rectangle_high, (int)priv->ch[i].rectangle_low);
priv->ch[i].waveform = UDAC_WAVE_RECTANGLE;
want_tog_timer = true;
break;
case CMD_SET_PHASE:;
uint16_t ph = pp_u16(pp);
uint32_t newphase = ph << UDAC_INDEX_SHIFT;
uint32_t oldphase = priv->ch[i].phase << UDAC_INDEX_SHIFT;
int32_t diff = newphase - oldphase;
priv->ch[i].counter += diff;
priv->ch[i].phase = ph;
break;
case CMD_SET_DITHER:;
uint8_t noisetype = pp_u8(pp); // 0-none, 1-random, 2-triangle
uint8_t noisebits = pp_u8(pp);
// type 0xFF = not set
if (noisetype <= 2) {
priv->ch[i].noise_type = (enum UDAC_Noise) noisetype;
}
// bits 0xFF = not set
if (noisebits >= 1 && noisebits <= 12) {
priv->ch[i].noise_level = (uint8_t) (noisebits - 1);
}
// dbg("Ch %d: Dither type %d, level %d", i,
// (int)priv->ch[i].noise_type,
// (int)priv->ch[i].noise_level);
want_reinit = true;
break;
default:
return E_UNKNOWN_COMMAND;
}
}
default:
return E_UNKNOWN_COMMAND;
}
if (want_reinit) {
UDAC_Reconfigure(unit);
}
if (want_tog_timer) {
UDAC_ToggleTimerIfNeeded(unit);
}
return E_SUCCESS;
}
// ------------------------------------------------------------------------
@ -44,7 +151,7 @@ static error_t UDAC_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command,
/** Unit template */
const UnitDriver UNIT_DAC = {
.name = "DAC",
.description = "Analog output",
.description = "Two-channel analog output with waveforms",
// Settings
.preInit = UDAC_preInit,
.cfgLoadBinary = UDAC_loadBinary,

@ -2,7 +2,6 @@
// Created by MightyPork on 2018/02/20.
//
#include <stm32f072xb.h>
#include "platform.h"
#define FCAP_INTERNAL

Loading…
Cancel
Save