fixes and start of ADC. Not really working yet

adc
Ondřej Hruška 6 years ago
parent 538a4876b2
commit 3ebc19fc2d
Signed by: MightyPork
GPG Key ID: 2C5FD5035250423D
  1. 2
      FreeRTOSConfig.h
  2. 8
      framework/resources.h
  3. 2
      framework/unit_registry.c
  4. 2
      freertos.c
  5. 1
      gex.mk
  6. 5
      platform/debug_uart.c
  7. 87
      platform/hw_utils.c
  8. 31
      platform/hw_utils.h
  9. 69
      platform/irq_dispatcher.c
  10. 2
      platform/platform.c
  11. 1
      platform/platform.h
  12. 2
      platform/timebase.c
  13. 1
      units/1wire/_ow_init.c
  14. 3
      units/1wire/_ow_internal.h
  15. 1
      units/1wire/_ow_search.c
  16. 1
      units/1wire/_ow_settings.c
  17. 2
      units/1wire/unit_1wire.c
  18. 225
      units/adc/_adc_init.c
  19. 22
      units/adc/_adc_internal.h
  20. 45
      units/adc/_adc_settings.c
  21. 4
      units/adc/unit_adc.c
  22. 2
      units/digital_in/_din_init.c
  23. 1
      units/digital_in/_din_settings.c
  24. 2
      units/digital_in/unit_din.c
  25. 1
      units/digital_out/_dout_init.c
  26. 1
      units/digital_out/_dout_settings.c
  27. 4
      units/i2c/_i2c_init.c
  28. 1
      units/i2c/_i2c_settings.c
  29. 6
      units/neopixel/_npx_init.c
  30. 6
      units/spi/_spi_init.c
  31. 2
      units/test/unit_test.c
  32. 4
      units/usart/_usart_dmas.c
  33. 11
      units/usart/_usart_init.c
  34. 4
      units/usart/_usart_internal.h
  35. 6
      units/usart/_usart_settings.c
  36. 8
      utils/malloc_safe.h
  37. 2
      utils/stacksmon.h

@ -153,7 +153,7 @@ to exclude the API function. */
#elif defined(GEX_PLAT_F072_DISCOVERY)
// This is for F072
#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY 3
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 3
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 1
#define configPRIO_BITS 2

@ -38,7 +38,7 @@ void rsc_init_registry(void);
* @param pin - pin number 0-15
* @return success
*/
error_t rsc_claim_pin(Unit *unit, char port_name, uint8_t pin);
error_t rsc_claim_pin(Unit *unit, char port_name, uint8_t pin) __attribute__((warn_unused_result));
/**
* Claim a resource by the Resource enum
@ -47,7 +47,7 @@ error_t rsc_claim_pin(Unit *unit, char port_name, uint8_t pin);
* @param rsc - resource to claim
* @return success
*/
error_t rsc_claim(Unit *unit, Resource rsc);
error_t rsc_claim(Unit *unit, Resource rsc) __attribute__((warn_unused_result));
/**
* Claim a range of resources (use for resources of the same type, e.g. USART1-5)
@ -57,7 +57,7 @@ error_t rsc_claim(Unit *unit, Resource rsc);
* @param rsc1 - last resource to claim
* @return success (E_SUCCESS = complete claim)
*/
error_t rsc_claim_range(Unit *unit, Resource rsc0, Resource rsc1);
error_t rsc_claim_range(Unit *unit, Resource rsc0, Resource rsc1) __attribute__((warn_unused_result));
/**
* Claim GPIOs by bitmask and port name, atomically.
@ -68,7 +68,7 @@ error_t rsc_claim_range(Unit *unit, Resource rsc0, Resource rsc1);
* @param pins - pins, bitmask
* @return success (E_SUCCESS = complete claim)
*/
error_t rsc_claim_gpios(Unit *unit, char port_name, uint16_t pins);
error_t rsc_claim_gpios(Unit *unit, char port_name, uint16_t pins) __attribute__((warn_unused_result));
/**
* Release all resources held by a unit, de-init held GPIOs

@ -606,7 +606,7 @@ void ureg_tick_units(void)
UlistEntry *li = ulist_head;
while (li != NULL) {
Unit *const pUnit = &li->unit;
if (pUnit->status == E_SUCCESS && pUnit->tick_interval > 0) {
if (pUnit && pUnit->data && pUnit->status == E_SUCCESS && pUnit->tick_interval > 0) {
if (pUnit->_tick_cnt == 0) {
if (pUnit->driver->updateTick) {
pUnit->driver->updateTick(pUnit);

@ -146,6 +146,8 @@ void MX_FREERTOS_Init(void) {
/* USER CODE BEGIN Init */
stackmon_register("Main", mainTaskStack, sizeof(mainTaskStack));
stackmon_register("Job+Msg", msgJobQueTaskStack, sizeof(msgJobQueTaskStack));
stackmon_register("Idle", xIdleStack, sizeof(xIdleStack));
stackmon_register("Timers", xTimersStack, sizeof(xTimersStack));
/* USER CODE END Init */
/* Create the mutex(es) */

@ -13,6 +13,7 @@ GEX_SRC_DIR = \
User/units/1wire \
User/units/i2c \
User/units/spi \
User/units/adc \
User/TinyFrame \
User/CWPack \
User/tasks

@ -66,7 +66,10 @@ void DebugUart_PreInit(void)
{
// configure AF only if platform uses AF numbers
#if !PLAT_NO_AFNUM
hw_configure_gpio_af(DEBUG_USART_PORT, DEBUG_USART_PIN, DEBUG_USART_AF);
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-result"
(void) hw_configure_gpio_af(DEBUG_USART_PORT, DEBUG_USART_PIN, DEBUG_USART_AF);
#pragma GCC diagnostic pop
#endif
hw_periph_clock_enable(DEBUG_USART);

@ -4,6 +4,7 @@
#include "platform.h"
#include <utils/avrlibc.h>
#include <math.h>
#include "hw_utils.h"
#include "macro.h"
@ -263,16 +264,64 @@ char * pinmask2str(uint16_t pins, char *buffer)
if (!first) {
b += SPRINTF(b, ", ");
}
if (start == (uint32_t)(i+1)) {
b += SPRINTF(b, "%"PRIu32, start);
}
// else if (start == (uint32_t)(i+2)) {
// // exception for 2-long ranges - don't show as range
// b += SPRINTF(b, "%"PRIu32",%"PRIu32, start, i + 1);
// }
else {
b += SPRINTF(b, "%"PRIu32"-%"PRIu32, start, i + 1);
}
first = false;
on = false;
}
}
}
return buffer;
}
char * pinmask2str_up(uint16_t pins, char *buffer)
{
char *b = buffer;
uint32_t start = 0;
bool on = false;
bool first = true;
// shortcut if none are set
if (pins == 0) {
buffer[0] = 0;
return buffer;
}
for (int32_t i = 0; i <= 16; i++) {
bool bit;
if (i == 16) {
bit = false;
} else {
bit = 0 != (pins & 1);
pins >>= 1;
}
if (bit) {
if (!on) {
start = (uint32_t) i;
on = true;
}
} else {
if (on) {
if (!first) {
b += SPRINTF(b, ", ");
}
if (start == (uint32_t)(i-1)) {
b += SPRINTF(b, "%"PRIu32, start);
}
else {
b += SPRINTF(b, "%"PRIu32"-%"PRIu32, start, i - 1);
}
first = false;
on = false;
}
@ -387,6 +436,36 @@ error_t hw_configure_sparse_pins(char port_name, uint16_t mask, GPIO_TypeDef **p
return E_SUCCESS;
}
/** Solve a timer/counter's count and prescaller value */
bool solve_timer(uint32_t base_freq, uint32_t required_freq, bool is16bit,
uint16_t *presc, uint32_t *count, float *real_freq)
{
if (required_freq == 0) return false;
const float fPresc = base_freq / required_freq;
uint32_t wCount = (uint32_t) lrintf(fPresc);
const uint32_t ceil = is16bit ? UINT16_MAX : UINT32_MAX;
uint32_t wPresc = 1;
while (wCount > ceil) {
wPresc <<= 1;
wCount >>= 1;
}
if (wPresc > ceil || count == 0) {
return false;
}
*count = wCount;
*presc = (uint16_t) wPresc;
if (wPresc * wCount == 0) return false;
*real_freq = (base_freq / (wPresc * wCount));
return true;
}
void hw_periph_clock_enable(void *periph)
{
// GPIOs are enabled by default on start-up

@ -78,6 +78,7 @@ uint16_t parse_pinmask(const char *value, bool *suc);
/**
* Convert a pin bitmap to the ASCII format understood by str_parse_pinmask()
* This is the downto variant (15..0)
*
* @param pins - sparse pin map
* @param buffer - output string buffer
@ -85,6 +86,16 @@ uint16_t parse_pinmask(const char *value, bool *suc);
*/
char * pinmask2str(uint16_t pins, char *buffer);
/**
* Convert a pin bitmap to the ASCII format understood by str_parse_pinmask()
* This is the ascending variant (0..15)
*
* @param pins - sparse pin map
* @param buffer - output string buffer
* @return the output buffer
*/
char * pinmask2str_up(uint16_t pins, char *buffer);
/**
* Spread packed port pins using a mask
*
@ -126,7 +137,7 @@ void hw_deinit_unit_pins(Unit *unit);
* @param ll_af - LL alternate function constant
* @return success
*/
error_t hw_configure_gpio_af(char port_name, uint8_t pin_num, uint32_t ll_af);
error_t hw_configure_gpio_af(char port_name, uint8_t pin_num, uint32_t ll_af) __attribute__((warn_unused_result));
/**
* Configure multiple pins using the bitmap pattern
@ -140,7 +151,7 @@ error_t hw_configure_gpio_af(char port_name, uint8_t pin_num, uint32_t ll_af);
*/
error_t hw_configure_sparse_pins(char port_name,
uint16_t mask, GPIO_TypeDef **port_dest,
uint32_t ll_mode, uint32_t ll_otype);
uint32_t ll_mode, uint32_t ll_otype) __attribute__((warn_unused_result));
/** Helper struct for defining alternate mappings */
struct PinAF {
@ -161,6 +172,22 @@ void hw_periph_clock_enable(void *periph);
*/
void hw_periph_clock_disable(void *periph);
/**
* Solve a timer/counter's count and prescaller value to meet the desired
* overflow frequency. The resulting values are the dividing factors;
* subtract 1 before writing them into the peripheral registers.
*
* @param[in] base_freq - the counter's input clock frequency in Hz
* @param[in] required_freq - desired overflow frequency
* @param[in] is16bit - limit counter to 16 bits (prescaller is always 16-bit)
* @param[out] presc - field for storing the computed prescaller value
* @param[out] count - field for storing the computed counter value
* @param[out] real_freq - field for storing the computed real frequency
* @return true on success
*/
bool solve_timer(uint32_t base_freq, uint32_t required_freq, bool is16bit,
uint16_t *presc, uint32_t *count, float *real_freq);
// ---------- LL extras ------------
static inline bool LL_DMA_IsActiveFlag_G(uint32_t isr_snapshot, uint8_t channel)

@ -61,6 +61,10 @@ static struct callbacks_ {
struct cbslot dma2_7;
struct cbslot dma2_8;
struct cbslot tim6;
struct cbslot tim7;
struct cbslot tim15;
// XXX add more callbacks here when needed
} callbacks;
@ -68,41 +72,62 @@ void irqd_init(void)
{
memset(&callbacks, 0, sizeof(callbacks));
// TODO move the priorities to some define
// NVIC_EnableIRQ(WWDG_IRQn); /*!< Window WatchDog Interrupt */
// NVIC_EnableIRQ(PVD_VDDIO2_IRQn); /*!< PVD & VDDIO2 Interrupt through EXTI Lines 16 and 31 */
// NVIC_EnableIRQ(RTC_IRQn); /*!< RTC Interrupt through EXTI Lines 17, 19 and 20 */
// NVIC_EnableIRQ(FLASH_IRQn); /*!< FLASH global Interrupt */
// NVIC_EnableIRQ(RCC_CRS_IRQn); /*!< RCC & CRS global Interrupt */
NVIC_EnableIRQ(EXTI0_1_IRQn); /*!< EXTI Line 0 and 1 Interrupt */
NVIC_EnableIRQ(EXTI2_3_IRQn); /*!< EXTI Line 2 and 3 Interrupt */
NVIC_EnableIRQ(EXTI4_15_IRQn); /*!< EXTI Line 4 to 15 Interrupt */
HAL_NVIC_SetPriority(EXTI0_1_IRQn, 2, 0);
HAL_NVIC_SetPriority(EXTI2_3_IRQn, 2, 0);
HAL_NVIC_SetPriority(EXTI4_15_IRQn, 2, 0);
// NVIC_EnableIRQ(TSC_IRQn); /*!< Touch Sensing Controller Interrupts */
NVIC_EnableIRQ(DMA1_Channel1_IRQn); /*!< DMA1 Channel 1 Interrupt */
NVIC_EnableIRQ(DMA1_Channel2_3_IRQn); /*!< DMA1 Channel 2 and Channel 3 Interrupt */
NVIC_EnableIRQ(DMA1_Channel4_5_6_7_IRQn); /*!< DMA1 Channel 4 to Channel 7 Interrupt */
HAL_NVIC_SetPriority(DMA1_Channel1_IRQn, 3, 0);
HAL_NVIC_SetPriority(DMA1_Channel2_3_IRQn, 3, 0);
HAL_NVIC_SetPriority(DMA1_Channel4_5_6_7_IRQn, 3, 0);
HAL_NVIC_SetPriority(DMA1_Channel1_IRQn, 2, 0);
HAL_NVIC_SetPriority(DMA1_Channel2_3_IRQn, 2, 0);
HAL_NVIC_SetPriority(DMA1_Channel4_5_6_7_IRQn, 2, 0);
// NVIC_EnableIRQ(ADC1_COMP_IRQn); /*!< ADC1 and COMP interrupts (ADC interrupt combined with EXTI Lines 21 and 22 */
// NVIC_EnableIRQ(TIM1_IRQn); /*!< TIM1 global Interrupt */
// NVIC_EnableIRQ(TIM2_IRQn); /*!< TIM2 global Interrupt */
// NVIC_EnableIRQ(TIM3_IRQn); /*!< TIM3 global Interrupt */
// NVIC_EnableIRQ(TIM6_DAC_IRQn); /*!< TIM6 global and DAC channel underrun error Interrupt */
// NVIC_EnableIRQ(TIM7_IRQn); /*!< TIM7 global Interrupt */
// --used internally-- NVIC_EnableIRQ(TIM14_IRQn); /*!< TIM14 global Interrupt */
// NVIC_EnableIRQ(TIM15_IRQn); /*!< TIM15 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
NVIC_EnableIRQ(TIM7_IRQn); /*!< TIM7 global Interrupt */
HAL_NVIC_SetPriority(TIM7_IRQn, 2, 0);
/* Tim14 is used for HAL timebase, because SysTick is used to time FreeRTOS and has the lowest priority. */
/* Tim14's priority is set to 0 in the init routine, which runs early in the startup sequence */
// NVIC_EnableIRQ(TIM14_IRQn); /*!< TIM14 global Interrupt */
NVIC_EnableIRQ(TIM15_IRQn); /*!< TIM15 global Interrupt */
HAL_NVIC_SetPriority(TIM15_IRQn, 2, 0);
// NVIC_EnableIRQ(TIM16_IRQn); /*!< TIM16 global Interrupt */
// NVIC_EnableIRQ(TIM17_IRQn); /*!< TIM17 global Interrupt */
// NVIC_EnableIRQ(I2C1_IRQn); /*!< I2C1 Event Interrupt & EXTI Line23 Interrupt (I2C1 wakeup) */
// NVIC_EnableIRQ(I2C2_IRQn); /*!< I2C2 Event Interrupt */
// NVIC_EnableIRQ(SPI1_IRQn); /*!< SPI1 global Interrupt */
// NVIC_EnableIRQ(SPI2_IRQn); /*!< SPI2 global Interrupt */
NVIC_EnableIRQ(USART1_IRQn); /*!< USART1 global Interrupt & EXTI Line25 Interrupt (USART1 wakeup) */
NVIC_EnableIRQ(USART2_IRQn); /*!< USART2 global Interrupt & EXTI Line26 Interrupt (USART2 wakeup) */
NVIC_EnableIRQ(USART3_4_IRQn); /*!< USART3 and USART4 global Interrupt */
HAL_NVIC_SetPriority(USART1_IRQn, 3, 0);
HAL_NVIC_SetPriority(USART2_IRQn, 3, 0);
HAL_NVIC_SetPriority(USART3_4_IRQn, 3, 0);
HAL_NVIC_SetPriority(USART1_IRQn, 2, 0);
HAL_NVIC_SetPriority(USART2_IRQn, 2, 0);
HAL_NVIC_SetPriority(USART3_4_IRQn, 2, 0);
// NVIC_EnableIRQ(CEC_CAN_IRQn); /*!< CEC and CAN global Interrupts & EXTI Line27 Interrupt */
// NVIC_EnableIRQ(TIM1_BRK_UP_TRG_COM_IRQn); /*!< TIM1 Break, Update, Trigger and Commutation Interrupt */ // - handled by hal msp init
@ -130,6 +155,10 @@ static struct cbslot *get_slot_for_periph(void *periph)
else if (periph == USART5) slot = &callbacks.usart5;
#endif
else if (periph == TIM6) slot = &callbacks.tim6;
else if (periph == TIM7) slot = &callbacks.tim7;
else if (periph == TIM15) slot = &callbacks.tim15;
else if (periph >= EXTIS[0] && periph <= EXTIS[15]) {
slot = &callbacks.exti[periph - EXTIS[0]];
}
@ -265,6 +294,26 @@ void EXTI4_15_IRQHandler(void)
}
// ------------ INTERRUPTS -------------
// TIM14 is used to generate HAL timebase and its handler is in the file "timebase.c"
void TIM6_DAC_IRQHandler(void)
{
CALL_IRQ_HANDLER(callbacks.tim6);
}
void TIM7_IRQHandler(void)
{
CALL_IRQ_HANDLER(callbacks.tim7);
}
void TIM15_IRQHandler(void)
{
CALL_IRQ_HANDLER(callbacks.tim15);
}
// other ISRs...
#if 0

@ -13,6 +13,7 @@
#include "units/neopixel/unit_neopixel.h"
#include "units/i2c/unit_i2c.h"
#include "units/1wire/unit_1wire.h"
#include "units/adc/unit_adc.h"
#include "units/test/unit_test.h"
#include "units/usart/unit_usart.h"
#include "units/spi/unit_spi.h"
@ -84,6 +85,7 @@ void plat_init_resources(void)
ureg_add_type(&UNIT_SPI);
ureg_add_type(&UNIT_USART);
ureg_add_type(&UNIT_1WIRE);
ureg_add_type(&UNIT_ADC);
// Free all present resources
{

@ -13,6 +13,7 @@
#include <stddef.h>
#include <string.h>
#include <malloc.h>
#include <math.h>
// FreeRTOS includes
#include <cmsis_os.h>

@ -15,6 +15,8 @@ HAL_StatusTypeDef HAL_InitTick(uint32_t TickPriority)
// This makes it a good choice for the timebase generation. We set it to generate
// an interrupt every 1 ms
assert_param(TickPriority == 0); // any other setting can lead to crashes
// - TIM14 is always up-counting
// - using APB1 clock
__HAL_RCC_TIM14_CLK_ENABLE();

@ -7,7 +7,6 @@
#define OW_INTERNAL
#include "_ow_internal.h"
#include "_ow_init.h"
/** Allocate data structure and set defaults */
error_t OW_preInit(Unit *unit)

@ -27,9 +27,6 @@ struct priv {
struct ow_search_state searchState;
};
/** Allocate data structure and set defaults */
error_t OW_preInit(Unit *unit);
/** Load from a binary buffer stored in Flash */
void OW_loadBinary(Unit *unit, PayloadParser *pp);

@ -9,7 +9,6 @@
#include "_ow_search.h"
#include "_ow_internal.h"
#include "_ow_low_level.h"
#include "_ow_checksum.h"
#include "_ow_commands.h"
void ow_search_init(Unit *unit, uint8_t command, bool test_checksums)

@ -7,7 +7,6 @@
#define OW_INTERNAL
#include "_ow_internal.h"
#include "_ow_settings.h"
/** Load from a binary buffer stored in Flash */
void OW_loadBinary(Unit *unit, PayloadParser *pp)

@ -9,8 +9,6 @@
// 1WIRE master
#define OW_INTERNAL
#include "_ow_internal.h"
#include "_ow_init.h"
#include "_ow_settings.h"
#include "_ow_low_level.h"
/**

@ -8,29 +8,241 @@
#define ADC_INTERNAL
#include "_adc_internal.h"
const uint32_t LL_ADC_SAMPLETIMES[] = {
LL_ADC_SAMPLINGTIME_1CYCLE_5,
LL_ADC_SAMPLINGTIME_7CYCLES_5,
LL_ADC_SAMPLINGTIME_13CYCLES_5,
LL_ADC_SAMPLINGTIME_28CYCLES_5,
LL_ADC_SAMPLINGTIME_41CYCLES_5,
LL_ADC_SAMPLINGTIME_55CYCLES_5,
LL_ADC_SAMPLINGTIME_71CYCLES_5,
LL_ADC_SAMPLINGTIME_239CYCLES_5,
};
/** Allocate data structure and set defaults */
error_t UADC_preInit(Unit *unit)
{
struct priv *priv = unit->data = calloc_ck(1, sizeof(struct priv));
if (priv == NULL) return E_OUT_OF_MEM;
//
priv->channels = 1; // PA0
priv->enable_tsense = false;
priv->enable_vref = false;
priv->sample_time = 0b010; // 13.5c
priv->frequency = 4; //1000
return E_SUCCESS;
}
static void UADC_DMA_Handler(void *arg)
{
Unit *unit = arg;
dbg("ADC DMA ISR hit");
assert_param(unit);
struct priv *priv = unit->data;
assert_param(priv);
const uint32_t isrsnapshot = priv->DMAx->ISR;
if (LL_DMA_IsActiveFlag_G(isrsnapshot, priv->dma_chnum)) {
bool tc = LL_DMA_IsActiveFlag_TC(isrsnapshot, priv->dma_chnum);
bool ht = LL_DMA_IsActiveFlag_HT(isrsnapshot, priv->dma_chnum);
// Here we have to either copy it somewhere else, or notify another thread (queue?)
// that the data is ready for reading
if (ht) {
uint16_t start = 0;
uint16_t end = (uint16_t) (priv->dma_buffer_size / 2);
// TODO handle first half
LL_DMA_ClearFlag_HT(priv->DMAx, priv->dma_chnum);
}
if (tc) {
uint16_t start = (uint16_t) (priv->dma_buffer_size / 2);
uint16_t end = (uint16_t) priv->dma_buffer_size;
// TODO handle second half
LL_DMA_ClearFlag_TC(priv->DMAx, priv->dma_chnum);
}
if (LL_DMA_IsActiveFlag_TE(isrsnapshot, priv->dma_chnum)) {
// this shouldn't happen - error
dbg("ADC DMA TE!");
LL_DMA_ClearFlag_TE(priv->DMAx, priv->dma_chnum);
}
}
}
/** Finalize unit set-up */
error_t UADC_init(Unit *unit)
{
bool suc = true;
struct priv *priv = unit->data;
//
// Written for F072 which has only one ADC
TRY(rsc_claim(unit, R_ADC1));
TRY(rsc_claim(unit, R_DMA1_1));
TRY(rsc_claim(unit, R_TIM15));
priv->DMAx = DMA1;
priv->DMA_CHx = DMA1_Channel1;
priv->dma_chnum = 1;
priv->ADCx = ADC1;
priv->ADCx_Common = ADC1_COMMON;
priv->TIMx = TIM15;
// ----------------------- CONFIGURE PINS --------------------------
{
// Claim and configure all analog pins
priv->nb_channels = 0;
for (uint8_t i = 0; i < 16; i++) {
if (priv->channels & (1 << i)) {
char c;
uint8_t num;
if (i <= 7) {
c = 'A';
num = i;
}
else if (i <= 9) {
c = 'B';
num = (uint8_t) (i - 8);
}
else {
c = 'C';
num = (uint8_t) (i - 10);
}
TRY(rsc_claim_pin(unit, c, num));
uint32_t ll_pin = hw_pin2ll(num, &suc);
GPIO_TypeDef *port = hw_port2periph(c, &suc);
assert_param(suc);
LL_GPIO_SetPinPull(port, ll_pin, LL_GPIO_PULL_NO);
LL_GPIO_SetPinMode(port, ll_pin, LL_GPIO_MODE_ANALOG);
priv->nb_channels++;
}
}
if (priv->enable_tsense) priv->nb_channels++;
if (priv->enable_vref) priv->nb_channels++;
if (priv->nb_channels == 0) {
dbg("!! Need at least 1 channel");
return E_BAD_CONFIG;
}
}
// ------------------- ENABLE CLOCKS --------------------------
{
// enable peripherals clock
hw_periph_clock_enable(priv->ADCx);
hw_periph_clock_enable(priv->TIMx);
}
// ------------------- CONFIGURE THE TIMER --------------------------
dbg("Setting up TIMER");
{
// Find suitable timer values
uint16_t presc;
uint32_t count;
float real_freq;
if (!solve_timer(PLAT_APB1_HZ, priv->frequency, true, &presc, &count,
&real_freq)) {
dbg("Failed to resolve timer params.");
return E_BAD_VALUE;
}
dbg("Frequency error %d ppm, presc %d, count %d",
(int) lrintf(1000000.0f * ((real_freq - priv->frequency) / (float)priv->frequency)), (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_EnableUpdateEvent(priv->TIMx);
LL_TIM_GenerateEvent_UPDATE(priv->TIMx); // load the prescaller value
}
// --------------------- CONFIGURE THE ADC ---------------------------
dbg("Setting up ADC");
{
// Calibrate the ADC
dbg("Wait for calib");
LL_ADC_StartCalibration(priv->ADCx);
while (LL_ADC_IsCalibrationOnGoing(priv->ADCx)) {}
dbg("ADC calibrated.");
uint32_t mask = 0;
if (priv->enable_vref) mask |= LL_ADC_PATH_INTERNAL_VREFINT;
if (priv->enable_tsense) mask |= LL_ADC_PATH_INTERNAL_TEMPSENSOR;
LL_ADC_SetCommonPathInternalCh(priv->ADCx_Common, mask);
LL_ADC_SetDataAlignment(priv->ADCx, LL_ADC_DATA_ALIGN_RIGHT);
LL_ADC_SetResolution(priv->ADCx, LL_ADC_RESOLUTION_12B);
LL_ADC_REG_SetDMATransfer(priv->ADCx, LL_ADC_REG_DMA_TRANSFER_UNLIMITED);
// configure channels
LL_ADC_REG_SetSequencerChannels(priv->ADCx, priv->channels);
if (priv->enable_tsense) LL_ADC_REG_SetSequencerChAdd(priv->ADCx, LL_ADC_CHANNEL_TEMPSENSOR);
if (priv->enable_vref) LL_ADC_REG_SetSequencerChAdd(priv->ADCx, LL_ADC_CHANNEL_VREFINT);
LL_ADC_REG_SetTriggerSource(priv->ADCx, LL_ADC_REG_TRIG_EXT_TIM15_TRGO);
LL_ADC_SetSamplingTimeCommonChannels(priv->ADCx, LL_ADC_SAMPLETIMES[priv->sample_time]);
LL_ADC_Enable(priv->ADCx);
}
// --------------------- CONFIGURE DMA -------------------------------
dbg("Setting up DMA");
{
// The length must be a 2*multiple of the number of channels
// this is a horrible way to do it but will work
uint16_t itemcount = (uint16_t) (priv->nb_channels * (uint16_t) (UADC_DMA_MAX_BUF_LEN / (2 * priv->nb_channels)));
priv->dma_buffer_size = (uint16_t) (itemcount * 2);
dbg("DMA item count is %d (%d bytes)", itemcount, priv->dma_buffer_size);
priv->dma_buffer = malloc_ck(priv->dma_buffer_size);
if (NULL == priv->dma_buffer) return E_OUT_OF_MEM;
assert_param(((uint32_t) priv->dma_buffer & 3) == 0); // must be aligned
{
LL_DMA_InitTypeDef init;
LL_DMA_StructInit(&init);
init.Direction = LL_DMA_DIRECTION_PERIPH_TO_MEMORY;
init.Mode = LL_DMA_MODE_CIRCULAR;
init.NbData = itemcount;
init.PeriphOrM2MSrcAddress = (uint32_t) &priv->ADCx->DR;
init.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_HALFWORD;
init.PeriphOrM2MSrcIncMode = LL_DMA_PERIPH_NOINCREMENT;
init.MemoryOrM2MDstAddress = (uint32_t) priv->dma_buffer;
init.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_HALFWORD;
init.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT;
assert_param(SUCCESS == LL_DMA_Init(priv->DMAx, priv->dma_chnum, &init));
irqd_attach(priv->DMA_CHx, UADC_DMA_Handler, unit);
// Interrupt on transfer 1/2 and complete
// We will capture the first and second half and send it while the other half is being filled.
LL_DMA_EnableIT_HT(priv->DMAx, priv->dma_chnum);
LL_DMA_EnableIT_TC(priv->DMAx, priv->dma_chnum);
}
LL_DMA_EnableChannel(priv->DMAx, priv->dma_chnum);
}
dbg("ADC inited, starting the timer ...");
// FIXME - temporary demo - counter start...
LL_TIM_EnableCounter(priv->TIMx);
return E_SUCCESS;
}
/** Tear down the unit */
void UADC_deInit(Unit *unit)
{
@ -38,7 +250,14 @@ void UADC_deInit(Unit *unit)
// de-init peripherals
if (unit->status == E_SUCCESS ) {
//
//LL_ADC_DeInit(priv->ADCx);
LL_ADC_CommonDeInit(priv->ADCx_Common);
LL_TIM_DeInit(priv->TIMx);
irqd_detach(priv->DMAx, UADC_DMA_Handler);
LL_DMA_DeInit(priv->DMAx, priv->dma_chnum);
free_ck(priv->dma_buffer);
}
// Release all resources, deinit pins

@ -14,10 +14,32 @@
/** Private data structure */
struct priv {
// settings
uint16_t channels; //!< bit flags (will be recorded in order 0-15)
bool enable_tsense; //!< append a signal from the temperature channel (voltage proportional to Tj)
bool enable_vref; //!< append a signal from the internal voltage reference
uint8_t sample_time; //!< 0-7 (corresponds to 1.5-239.5 cycles) - time for the sampling capacitor to charge
uint32_t frequency; //!< Timer frequency in Hz. Note: not all frequencies can be achieved accurately
// TODO averaging (maybe a separate component?)
// TODO threshold watchdog with hysteresis (maybe a separate component?)
// TODO trigger level, edge direction, hold-off, pre-trigger buffer (extract from the DMA buffer)
// internal state
ADC_TypeDef *ADCx;
ADC_Common_TypeDef *ADCx_Common;
TIM_TypeDef *TIMx;
DMA_TypeDef *DMAx;
uint8_t dma_chnum;
DMA_Channel_TypeDef *DMA_CHx;
uint16_t *dma_buffer;
uint8_t nb_channels; // nr of enabled adc channels
uint16_t dma_buffer_size; // real number of bytes
};
// max size of the DMA buffer. The actual buffer size will be adjusted to accommodate
// an even number of sample groups (sets of channels)
#define UADC_DMA_MAX_BUF_LEN 512
/** Allocate data structure and set defaults */
error_t UADC_preInit(Unit *unit);

@ -16,7 +16,11 @@ void UADC_loadBinary(Unit *unit, PayloadParser *pp)
uint8_t version = pp_u8(pp);
(void)version;
//
priv->channels = pp_u16(pp);
priv->enable_tsense = pp_bool(pp);
priv->enable_vref = pp_bool(pp);
priv->sample_time = pp_u8(pp);
priv->frequency = pp_u32(pp);
}
/** Write to a binary buffer for storing in Flash */
@ -26,7 +30,11 @@ void UADC_writeBinary(Unit *unit, PayloadBuilder *pb)
pb_u8(pb, 0); // version
//
pb_u16(pb, priv->channels);
pb_bool(pb, priv->enable_tsense);
pb_bool(pb, priv->enable_vref);
pb_u8(pb, priv->sample_time);
pb_u32(pb, priv->frequency);
}
// ------------------------------------------------------------------------
@ -37,8 +45,21 @@ error_t UADC_loadIni(Unit *unit, const char *key, const char *value)
bool suc = true;
struct priv *priv = unit->data;
if (false) {
//
if (streq(key, "channels")) {
priv->channels = parse_pinmask(value, &suc);
}
else if (streq(key, "enable_tsense")) {
priv->enable_tsense = str_parse_yn(value, &suc);
}
else if (streq(key, "enable_vref")) {
priv->enable_vref = str_parse_yn(value, &suc);
}
else if (streq(key, "sample_time")) {
priv->sample_time = (uint8_t) avr_atoi(value);
if (priv->sample_time > 7) return E_BAD_VALUE;
}
else if (streq(key, "frequency")) {
priv->frequency = (uint32_t) avr_atoi(value);
}
else {
return E_BAD_KEY;
@ -53,6 +74,20 @@ void UADC_writeIni(Unit *unit, IniWriter *iw)
{
struct priv *priv = unit->data;
//
iw_comment(iw, "Enabled channels, comma separated");
iw_comment(iw, "0-7 = A0-A7, 8-9 = B0-B1, 10-15 = C0-C5");
iw_entry(iw, "channels", "%s", pinmask2str_up(priv->channels, unit_tmp512));
iw_comment(iw, "Enable Tsense channel");
iw_entry(iw, "enable_tsense", str_yn(priv->enable_tsense));
iw_comment(iw, "Enable Vref channel");
iw_entry(iw, "enable_vref", str_yn(priv->enable_tsense));
iw_comment(iw, "Sampling time (0-7)");
iw_entry(iw, "sample_time", "%d", (int)priv->sample_time);
iw_comment(iw, "Sampling frequency (Hz)");
iw_entry(iw, "frequency", "%d", (int)priv->frequency);
}

@ -11,7 +11,7 @@
// ------------------------------------------------------------------------
enum TplCmd_ {
//
CMD_DUMMY,
};
/** Handle a request message */
@ -28,7 +28,7 @@ static error_t UADC_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, P
/** Unit template */
const UnitDriver UNIT_ADC = {
.name = "ADC",
.description = "Template unit",
.description = "Analog inputs",
// Settings
.preInit = UADC_preInit,
.cfgLoadBinary = UADC_loadBinary,

@ -7,8 +7,6 @@
#define DIN_INTERNAL
#include "_din_internal.h"
#include "_din_init.h"
#include "_din_exti.h"
/** Allocate data structure and set defaults */
error_t DIn_preInit(Unit *unit)

@ -7,7 +7,6 @@
#define DIN_INTERNAL
#include "_din_internal.h"
#include "_din_settings.h"
/** Load from a binary buffer stored in Flash */
void DIn_loadBinary(Unit *unit, PayloadParser *pp)

@ -7,8 +7,6 @@
#define DIN_INTERNAL
#include "_din_internal.h"
#include "_din_settings.h"
#include "_din_init.h"
// ------------------------------------------------------------------------

@ -7,7 +7,6 @@
#define DOUT_INTERNAL
#include "_dout_internal.h"
#include "_dout_init.h"
/** Allocate data structure and set defaults */
error_t DOut_preInit(Unit *unit)

@ -7,7 +7,6 @@
#define DOUT_INTERNAL
#include "_dout_internal.h"
#include "_dout_settings.h"
/** Load from a binary buffer stored in Flash */
void DOut_loadBinary(Unit *unit, PayloadParser *pp)

@ -118,8 +118,8 @@ error_t UI2C_init(Unit *unit)
TRY(rsc_claim_pin(unit, portname, pin_sda));
TRY(rsc_claim_pin(unit, portname, pin_scl));
hw_configure_gpio_af(portname, pin_sda, af_i2c);
hw_configure_gpio_af(portname, pin_scl, af_i2c);
TRY(hw_configure_gpio_af(portname, pin_sda, af_i2c));
TRY(hw_configure_gpio_af(portname, pin_scl, af_i2c));
hw_periph_clock_enable(priv->periph);

@ -7,7 +7,6 @@
#define I2C_INTERNAL
#include "_i2c_internal.h"
#include "_i2c_settings.h"
/** Load from a binary buffer stored in Flash */
void UI2C_loadBinary(Unit *unit, PayloadParser *pp)

@ -13,10 +13,10 @@
error_t Npx_preInit(Unit *unit)
{
struct priv *priv = unit->data = calloc_ck(1, sizeof(struct priv));
if (priv == NULL)
if (priv == NULL) return E_OUT_OF_MEM;
// some defaults
priv->pin_number = 0;
// some defaults
priv->pin_number = 0;
priv->port_name = 'A';
priv->pixels = 1;

@ -132,9 +132,9 @@ error_t USPI_init(Unit *unit)
TRY(rsc_claim_pin(unit, spi_portname, pin_miso));
TRY(rsc_claim_pin(unit, spi_portname, pin_sck));
hw_configure_gpio_af(spi_portname, pin_mosi, af_spi);
hw_configure_gpio_af(spi_portname, pin_miso, af_spi);
hw_configure_gpio_af(spi_portname, pin_sck, af_spi);
TRY(hw_configure_gpio_af(spi_portname, pin_mosi, af_spi));
TRY(hw_configure_gpio_af(spi_portname, pin_miso, af_spi));
TRY(hw_configure_gpio_af(spi_portname, pin_sck, af_spi));
// configure SSN GPIOs
{

@ -112,7 +112,7 @@ static void bw_dump(struct bulk_write *bulk, const uint8_t *chunk, uint32_t len)
}
dbg("\r\nBulk write at %d, len %d", (int)bulk->offset, (int)len);
PUTSN((const char *) chunk, len);
PUTSN((const char *) chunk, (uint16_t) len);
PUTS("\r\n");
}

@ -190,7 +190,6 @@ error_t UUSART_SetupDMAs(Unit *unit)
LL_DMA_EnableChannel(priv->dma, priv->dma_rx_chnum);
LL_DMA_EnableChannel(priv->dma, priv->dma_tx_chnum);
// TODO also set up usart timeout interrupt that grabs whatever is in the DMA buffer and sends it
return E_SUCCESS;
}
@ -205,7 +204,7 @@ static void UUSART_DMA_RxHandler(void *arg)
struct priv *priv = unit->data;
assert_param(priv);
uint32_t isrsnapshot = priv->dma->ISR;
const uint32_t isrsnapshot = priv->dma->ISR;
if (LL_DMA_IsActiveFlag_G(isrsnapshot, priv->dma_rx_chnum)) {
bool tc = LL_DMA_IsActiveFlag_TC(isrsnapshot, priv->dma_rx_chnum);
@ -228,6 +227,7 @@ static void UUSART_DMA_RxHandler(void *arg)
if (LL_DMA_IsActiveFlag_TE(isrsnapshot, priv->dma_rx_chnum)) {
// this shouldn't happen
dbg("USART DMA TE!");
LL_DMA_ClearFlag_TE(priv->dma, priv->dma_rx_chnum);
}
}

@ -1,7 +1,6 @@
//
// Created by MightyPork on 2018/01/14.
//
#include <platform/irq_dispatcher.h>
#include "platform.h"
#include "unit_base.h"
@ -25,7 +24,7 @@ error_t UUSART_preInit(Unit *unit)
priv->baudrate = 115200;
priv->parity = 0; //!< 0-none, 1-odd, 2-even
priv->stopbits = 1; //!< 0-half, 1-one, 2-1.5, 3-two
priv->direction = 3; // RXTX
priv->direction = UUSART_DIRECTION_RXTX; // RXTX
priv->hw_flow_control = false;
priv->clock_output = false;
@ -205,7 +204,7 @@ static inline error_t UUSART_configPins(Unit *unit)
if (pins_wanted[i]) {
if (mappings[i].port == 0) return E_BAD_CONFIG;
TRY(rsc_claim_pin(unit, mappings[i].port, mappings[i].pin));
hw_configure_gpio_af(mappings[i].port, mappings[i].pin, mappings[i].af);
TRY(hw_configure_gpio_af(mappings[i].port, mappings[i].pin, mappings[i].af));
}
}
@ -252,9 +251,9 @@ error_t UUSART_init(Unit *unit)
: LL_USART_STOPBITS_2);
LL_USART_SetTransferDirection(priv->periph,
priv->direction == 1 ? LL_USART_DIRECTION_RX :
priv->direction == 2 ? LL_USART_DIRECTION_TX
: LL_USART_DIRECTION_TX_RX);
(priv->direction == UUSART_DIRECTION_RX) ? LL_USART_DIRECTION_RX :
(priv->direction == UUSART_DIRECTION_TX) ? LL_USART_DIRECTION_TX
: LL_USART_DIRECTION_TX_RX);
LL_USART_SetHWFlowCtrl(priv->periph,
priv->hw_flow_control == 0 ? LL_USART_HWCONTROL_NONE :

@ -17,6 +17,10 @@
#define UUSART_RXBUF_LEN 128
#define UUSART_TXBUF_LEN 128
#define UUSART_DIRECTION_RX 1
#define UUSART_DIRECTION_TX 2
#define UUSART_DIRECTION_RXTX 3
/** Private data structure */
struct priv {
uint8_t periph_num; //!< 1-6

@ -104,9 +104,9 @@ error_t UUSART_loadIni(Unit *unit, const char *key, const char *value)
}
else if (streq(key, "direction")) {
priv->direction = (uint8_t) str_parse_3(value,
"RX", 1,
"TX", 2,
"RXTX", 3, &suc);
"RX", UUSART_DIRECTION_RX,
"TX", UUSART_DIRECTION_TX,
"RXTX", UUSART_DIRECTION_RXTX, &suc);
}
else if (streq(key, "hw-flow-control")) {
priv->hw_flow_control = (uint8_t) str_parse_4(value,

@ -15,10 +15,10 @@
#include <stdint.h>
#include <stdbool.h>
void *malloc_ck_do(size_t size, const char* file, uint32_t line) __attribute__((malloc));
void *calloc_ck_do(size_t nmemb, size_t size, const char* file, uint32_t line) __attribute__((malloc));
char *strdup_ck_do(const char *s, const char* file, uint32_t line) __attribute__((malloc));
char *strndup_ck_do(const char *s, uint32_t len, const char* file, uint32_t line) __attribute__((malloc));
void *malloc_ck_do(size_t size, const char* file, uint32_t line) __attribute__((malloc,warn_unused_result));
void *calloc_ck_do(size_t nmemb, size_t size, const char* file, uint32_t line) __attribute__((malloc,warn_unused_result));
char *strdup_ck_do(const char *s, const char* file, uint32_t line) __attribute__((malloc,warn_unused_result));
char *strndup_ck_do(const char *s, uint32_t len, const char* file, uint32_t line) __attribute__((malloc,warn_unused_result));
#if DEBUG_MALLOC

@ -12,7 +12,7 @@
#if USE_STACK_MONITOR
/** Number of tracked stacks, max */
#define STACK_NUM 3
#define STACK_NUM 4
/**
* Check canaries and trap if they're dead

Loading…
Cancel
Save