merge elf loading and adc streaming

pull/3/head
Clyne 4 years ago
commit 989f4038c6

1
.gitignore vendored

@ -3,5 +3,6 @@ ChibiOS_*
**/.*
gui/stmdspgui
**/*.o
**/*.so
perf*

@ -0,0 +1,14 @@
all:
@arm-none-eabi-gcc -mcpu=cortex-m4 -mthumb -Os --specs=nosys.specs -nostartfiles -fPIE -c test.cpp
@arm-none-eabi-ld -shared -n -N -z max-page-size=512 -Ttext-segment=0 \
test.o -o test.so
@arm-none-eabi-strip -s -S --strip-unneeded test.so
@arm-none-eabi-objcopy --remove-section .dynsym \
--remove-section .dynstr \
--remove-section .dynamic \
--remove-section .hash \
--remove-section .ARM.exidx \
--remove-section .ARM.attributes \
--remove-section .comment \
test.so

@ -0,0 +1,15 @@
#include <cstdint>
using adcsample_t = uint16_t;
__attribute__((section(".process_data")))
void process_data(adcsample_t *samples, unsigned int size);
////////////////////////////////////////////////////////////////////////////////
void process_data(adcsample_t *samples, unsigned int size)
{
size--;
for (unsigned int i = 0; i < size; i++)
samples[i] = samples[i] * 80 / 100 + samples[i + 1] * 20 / 100;
}

@ -18,7 +18,7 @@ constexpr static const ADCConfig adc_config = {
.difsel = 0
};
void adc_read_callback(ADCDriver *);
static void adc_read_callback(ADCDriver *);
/*constexpr*/ static ADCConversionGroup adc_group_config = {
.circular = false,
@ -45,51 +45,88 @@ constexpr static const GPTConfig gpt_config = {
};
static bool adc_is_read_finished = false;
static bool adc_is_read_continuous = false;
static adcsample_t *adc_current_buffer = nullptr;
static size_t adc_current_buffer_size = 0;
static adc_operation_t adc_operation_func = nullptr;
static adc::operation_t adc_operation_func = nullptr;
void adc_init()
namespace adc
{
palSetPadMode(GPIOA, 0, PAL_MODE_INPUT_ANALOG);
gptStart(gptd, &gpt_config);
adcStart(adcd, &adc_config);
adcSTM32EnableVREF(adcd);
}
adcsample_t *adc_read(adcsample_t *buffer, size_t count)
{
adc_is_read_finished = false;
adc_is_read_continuous = false;
adc_group_config.circular = false;
adcStartConversion(adcd, &adc_group_config, buffer, count);
gptStartContinuous(gptd, 100); // 10kHz
while (!adc_is_read_finished);
return buffer;
}
void adc_read_start(adc_operation_t operation_func, adcsample_t *buffer, size_t count)
{
adc_is_read_continuous = true;
adc_current_buffer = buffer;
adc_current_buffer_size = count;
adc_operation_func = operation_func;
adc_group_config.circular = true;
adcStartConversion(adcd, &adc_group_config, buffer, count);
gptStartContinuous(gptd, 100); // 10kHz
}
void init()
{
palSetPadMode(GPIOA, 0, PAL_MODE_INPUT_ANALOG);
gptStart(gptd, &gpt_config);
adcStart(adcd, &adc_config);
adcSTM32EnableVREF(adcd);
}
adcsample_t *read(adcsample_t *buffer, size_t count)
{
adc_is_read_finished = false;
adc_group_config.circular = false;
adcStartConversion(adcd, &adc_group_config, buffer, count);
gptStartContinuous(gptd, 100); // 10kHz
while (!adc_is_read_finished);
return buffer;
}
void adc_read_stop()
{
adc_is_read_continuous = false;
gptStopTimer(gptd);
void read_start(operation_t operation_func, adcsample_t *buffer, size_t count)
{
adc_current_buffer = buffer;
adc_current_buffer_size = count;
adc_operation_func = operation_func;
adc_group_config.circular = true;
adcStartConversion(adcd, &adc_group_config, buffer, count);
gptStartContinuous(gptd, 100); // 10kHz
}
void read_stop()
{
gptStopTimer(gptd);
adc_group_config.circular = false;
adc_current_buffer = nullptr;
adc_current_buffer_size = 0;
adc_operation_func = nullptr;
}
void set_rate(rate r)
{
uint32_t val = 0;
switch (r) {
case rate::R2P5:
val = ADC_SMPR1_SMP_AN5(ADC_SMPR_SMP_2P5);
break;
case rate::R6P5:
val = ADC_SMPR1_SMP_AN5(ADC_SMPR_SMP_6P5);
break;
case rate::R12P5:
val = ADC_SMPR1_SMP_AN5(ADC_SMPR_SMP_12P5);
break;
case rate::R24P5:
val = ADC_SMPR1_SMP_AN5(ADC_SMPR_SMP_24P5);
break;
case rate::R47P5:
val = ADC_SMPR1_SMP_AN5(ADC_SMPR_SMP_47P5);
break;
case rate::R92P5:
val = ADC_SMPR1_SMP_AN5(ADC_SMPR_SMP_92P5);
break;
case rate::R247P5:
val = ADC_SMPR1_SMP_AN5(ADC_SMPR_SMP_247P5);
break;
case rate::R640P5:
val = ADC_SMPR1_SMP_AN5(ADC_SMPR_SMP_640P5);
break;
}
adc_group_config.smpr[0] = val;
}
}
void adc_read_callback(ADCDriver *driver)
{
if (!adc_is_read_continuous) {
if (!adc_group_config.circular) {
gptStopTimer(gptd);
adc_is_read_finished = true;
} else if (adc_operation_func != nullptr) {
@ -104,37 +141,3 @@ void adc_read_callback(ADCDriver *driver)
}
}
void adc_set_rate(ADCRate rate)
{
uint32_t val = 0;
switch (rate) {
case ADCRate::R2P5:
val = ADC_SMPR1_SMP_AN5(ADC_SMPR_SMP_2P5);
break;
case ADCRate::R6P5:
val = ADC_SMPR1_SMP_AN5(ADC_SMPR_SMP_6P5);
break;
case ADCRate::R12P5:
val = ADC_SMPR1_SMP_AN5(ADC_SMPR_SMP_12P5);
break;
case ADCRate::R24P5:
val = ADC_SMPR1_SMP_AN5(ADC_SMPR_SMP_24P5);
break;
case ADCRate::R47P5:
val = ADC_SMPR1_SMP_AN5(ADC_SMPR_SMP_47P5);
break;
case ADCRate::R92P5:
val = ADC_SMPR1_SMP_AN5(ADC_SMPR_SMP_92P5);
break;
case ADCRate::R247P5:
val = ADC_SMPR1_SMP_AN5(ADC_SMPR_SMP_247P5);
break;
case ADCRate::R640P5:
val = ADC_SMPR1_SMP_AN5(ADC_SMPR_SMP_640P5);
break;
}
adc_group_config.smpr[0] = val;
}

@ -14,24 +14,27 @@
#include "hal.h"
enum class ADCRate {
R2P5,
R6P5,
R12P5,
R24P5,
R47P5,
R92P5,
R247P5,
R640P5
};
namespace adc
{
using operation_t = void (*)(adcsample_t *buffer, size_t count);
using adc_operation_t = void (*)(adcsample_t *buffer, size_t count);
void adc_init();
adcsample_t *adc_read(adcsample_t *buffer, size_t count);
void adc_read_start(adc_operation_t operation_func, adcsample_t *buffer, size_t count);
void adc_read_stop();
void adc_set_rate(ADCRate rate);
enum class rate {
R2P5,
R6P5,
R12P5,
R24P5,
R47P5,
R92P5,
R247P5,
R640P5
};
void init();
adcsample_t *read(adcsample_t *buffer, size_t count);
void read_start(operation_t operation_func, adcsample_t *buffer, size_t count);
void read_stop();
void set_rate(rate r);
}
#endif // STMDSP_ADC_HPP_

@ -34,24 +34,27 @@ constexpr static const GPTConfig gpt_config = {
.dier = 0
};
void dac_init()
namespace dac
{
palSetPadMode(GPIOA, 4, PAL_MODE_INPUT_ANALOG);
//palSetPadMode(GPIOA, 5, PAL_MODE_INPUT_ANALOG);
dacStart(dacd, &dac_config);
gptStart(gptd, &gpt_config);
}
void dac_write_start(dacsample_t *buffer, size_t count)
{
dacStartConversion(dacd, &dac_group_config, buffer, count);
gptStartContinuous(gptd, 1);
}
void dac_write_stop()
{
gptStopTimer(gptd);
dacStopConversion(dacd);
void init()
{
palSetPadMode(GPIOA, 4, PAL_MODE_INPUT_ANALOG);
//palSetPadMode(GPIOA, 5, PAL_MODE_INPUT_ANALOG);
dacStart(dacd, &dac_config);
gptStart(gptd, &gpt_config);
}
void write_start(dacsample_t *buffer, size_t count)
{
dacStartConversion(dacd, &dac_group_config, buffer, count);
gptStartContinuous(gptd, 1);
}
void write_stop()
{
gptStopTimer(gptd);
dacStopConversion(dacd);
}
}

@ -14,9 +14,12 @@
#include "hal.h"
void dac_init();
void dac_write_start(dacsample_t *buffer, size_t count);
void dac_write_stop();
namespace dac
{
void init();
void write_start(dacsample_t *buffer, size_t count);
void write_stop();
}
#endif // STMDSP_DAC_HPP_

@ -0,0 +1,93 @@
#ifndef STMDSP_ELF_FORMAT_HPP_
#define STMDSP_ELF_FORMAT_HPP_
#include <cstdint>
#define EI_NIDENT 16
#define PT_NULL 0
#define PT_LOAD 1
#define PT_DYNAMIC 2
#define PT_INTERP 3
#define PT_NOTE 4
#define PT_SHLIB 5
#define PT_PHDR 6
#define PT_RESERVED 0x70000000
#define ELF32_ST_BIND(i) ((i) >> 4)
#define ELF32_ST_TYPE(i) ((i) & 0xF)
#define ELF32_ST_INFO(b, t) (((b) << 4) + ((t) & 0xF))
#define ELF32_R_SYM(i) ((i) >> 8)
#define ELF32_R_TYPE(i) ((i) & 0xFF)
#define ELF32_R_INFO(s, t) (((s) << 8) + ((t) & 0xFF))
typedef uint32_t Elf32_Addr;
typedef uint16_t Elf32_Half;
typedef uint32_t Elf32_Off;
typedef uint32_t Elf32_Sword;
typedef uint32_t Elf32_Word;
typedef struct {
unsigned char e_ident[EI_NIDENT];
Elf32_Half e_type;
Elf32_Half e_machine;
Elf32_Word e_version;
Elf32_Addr e_entry;
Elf32_Off e_phoff;
Elf32_Off e_shoff;
Elf32_Word e_flags;
Elf32_Half e_ehsize;
Elf32_Half e_phentsize;
Elf32_Half e_phnum;
Elf32_Half e_shentsize;
Elf32_Half e_shnum;
Elf32_Half e_shstrndx;
} __attribute__((packed)) Elf32_Ehdr;
typedef struct {
Elf32_Word sh_name;
Elf32_Word sh_type;
Elf32_Word sh_flags;
Elf32_Addr sh_addr;
Elf32_Off sh_offset;
Elf32_Word sh_size;
Elf32_Word sh_link;
Elf32_Word sh_info;
Elf32_Word sh_addralign;
Elf32_Word sh_entsize;
} __attribute__((packed)) Elf32_Shdr;
typedef struct {
Elf32_Word st_name;
Elf32_Addr st_value;
Elf32_Word st_size;
unsigned char st_info;
unsigned char st_other;
Elf32_Half st_shndx;
} __attribute__((packed)) Elf32_Sym;
typedef struct {
Elf32_Addr r_offset;
Elf32_Word r_info;
} __attribute__((packed)) Elf32_Rel;
typedef struct {
Elf32_Addr r_offset;
Elf32_Word r_info;
Elf32_Sword r_addend;
} __attribute__((packed)) Elf32_Rela;
typedef struct {
Elf32_Word p_type;
Elf32_Off p_offset;
Elf32_Addr p_vaddr;
Elf32_Addr p_paddr;
Elf32_Word p_filesz;
Elf32_Word p_memsz;
Elf32_Word p_flags;
Elf32_Word p_align;
} __attribute__((packed)) Elf32_Phdr;
#endif // STMDSP_ELF_FORMAT_HPP_

@ -0,0 +1,77 @@
#include "elf_load.hpp"
#include "elf_format.hpp"
#include <algorithm>
#include <cstring>
extern void *elf_load_offset;
static const unsigned char elf_header[] = { '\177', 'E', 'L', 'F' };
template<typename T>
constexpr static auto ptr_from_offset(void *base, uint32_t offset)
{
return reinterpret_cast<T>(reinterpret_cast<uint8_t *>(base) + offset);
}
static Elf32_Shdr *find_section(Elf32_Ehdr *ehdr, const char *name);
namespace elf {
entry_t elf_load(void *elf_data)
{
auto ehdr = reinterpret_cast<Elf32_Ehdr *>(elf_data);
if (std::equal(ehdr->e_ident, ehdr->e_ident + 4, elf_header))
return nullptr;
auto phdr = ptr_from_offset<Elf32_Phdr *>(elf_data, ehdr->e_phoff);
for (Elf32_Half i = 0; i < ehdr->e_phnum; i++) {
if (phdr->p_type == PT_LOAD) {
std::memcpy(ptr_from_offset<void *>(elf_load_offset, phdr->p_vaddr),
ptr_from_offset<void *>(elf_data, phdr->p_offset),
phdr->p_filesz);
//break;
}
}
// Zero .bss section
if (auto bss_section = find_section(ehdr, ".bss"); bss_section) {
auto bss = ptr_from_offset<uint32_t *>(elf_load_offset, bss_section->sh_addr);
std::fill(bss, bss + bss_section->sh_size / sizeof(uint32_t), 0);
}
// Fix global offset table (GOT) entries
if (auto got_section = find_section(ehdr, ".got"); got_section) {
auto got = ptr_from_offset<void **>(elf_load_offset, got_section->sh_addr);
for (size_t i = 0; i < got_section->sh_size / sizeof(void *); i++)
got[i] = ptr_from_offset<void *>(got[i], reinterpret_cast<uint32_t>(elf_load_offset));
}
//// Run any initial constructors
//if (auto init_section = find_section(ehdr, ".init_array"); init_section) {
// auto init_array = reinterpret_cast<void (**)()>(elf_load_offset + init_section->sh_addr);
// std::for_each(init_array, init_array + init_section->sh_size / sizeof(void (*)()),
// [elf_load_offset](auto func) { (func + elf_load_offset)(); });
//}
return ptr_from_offset<entry_t>(elf_load_offset, ehdr->e_entry);
}
} // namespace elf
Elf32_Shdr *find_section(Elf32_Ehdr *ehdr, const char *name)
{
auto shdr = ptr_from_offset<Elf32_Shdr *>(ehdr, ehdr->e_shoff);
auto shdr_str = ptr_from_offset<Elf32_Shdr *>(ehdr,
ehdr->e_shoff + ehdr->e_shstrndx * ehdr->e_shentsize);
for (Elf32_Half i = 0; i < ehdr->e_shnum; i++) {
char *section = ptr_from_offset<char *>(ehdr, shdr_str->sh_offset) + shdr->sh_name;
if (!strcmp(section, name))
return shdr;
shdr = ptr_from_offset<Elf32_Shdr *>(shdr, ehdr->e_shentsize);
}
return 0;
}

@ -0,0 +1,12 @@
#ifndef ELF_LOAD_HPP_
#define ELF_LOAD_HPP_
namespace elf
{
using entry_t = void (*)();
entry_t load(void *file_data);
}
#endif // ELF_LOAD_HPP_

@ -35,45 +35,45 @@ int main()
palSetPadMode(GPIOA, 5, PAL_MODE_OUTPUT_PUSHPULL); // LED
adc_init();
dac_init();
usbserial_init();
adc::init();
dac::init();
usbserial::init();
static unsigned int dac_sample_count = 2048;
while (true) {
if (usbserial_is_active()) {
if (usbserial::is_active()) {
// Expect to receive a byte command 'packet'.
if (char cmd[3]; usbserial_read(&cmd, 1) > 0) {
if (char cmd[3]; usbserial::read(&cmd, 1) > 0) {
switch (cmd[0]) {
case 'r': // Read in analog signal
if (usbserial_read(&cmd[1], 2) < 2)
if (usbserial::read(&cmd[1], 2) < 2)
break;
if (auto count = std::min(static_cast<unsigned int>(cmd[1] | (cmd[2] << 8)), adc_samples.size()); count > 0) {
adc_read(&adc_samples[0], count);
usbserial_write(adc_samples.data(), count * sizeof(adcsample_t));
adc::read(&adc_samples[0], count);
usbserial::write(adc_samples.data(), count * sizeof(adcsample_t));
}
break;
case 'R':
adc_read_start(signal_operate, &adc_samples[0], adc_samples.size() * sizeof(adcsample_t));
adc::read_start(signal_operate, &adc_samples[0], adc_samples.size() * sizeof(adcsample_t));
break;
case 'S':
adc_read_stop();
adc::read_stop();
break;
case 'W':
if (usbserial_read(&cmd[1], 2) < 2)
if (usbserial::read(&cmd[1], 2) < 2)
break;
if (auto count = std::min(static_cast<unsigned int>(cmd[1] | (cmd[2] << 8)), dac_samples.size()); count > 0)
dac_sample_count = count;
else
dac_write_stop();
dac::write_stop();
break;
case 'w':
if (usbserial_read(&dac_samples[0], 2 * dac_sample_count) != 2 * dac_sample_count)
if (usbserial::read(&dac_samples[0], 2 * dac_sample_count) != 2 * dac_sample_count)
break;
dac_write_start(&dac_samples[0], dac_sample_count);
dac::write_start(&dac_samples[0], dac_sample_count);
break;
case 'i': // Identify ourself as an stmdsp device
usbserial_write("stmdsp", 6);
usbserial::write("stmdsp", 6);
break;
default:
break;

@ -15,35 +15,38 @@
constexpr static const auto sdud = &SDU1;
void usbserial_init()
namespace usbserial
{
palSetPadMode(GPIOA, 11, PAL_MODE_ALTERNATE(10));
palSetPadMode(GPIOA, 12, PAL_MODE_ALTERNATE(10));
sduObjectInit(sdud);
sduStart(sdud, &serusbcfg);
// Reconnect bus so device can re-enumerate on reset
usbDisconnectBus(serusbcfg.usbp);
chThdSleepMilliseconds(1500);
usbStart(serusbcfg.usbp, &usbcfg);
usbConnectBus(serusbcfg.usbp);
}
bool usbserial_is_active()
{
return sdud->config->usbp->state == USB_ACTIVE;
}
size_t usbserial_read(void *buffer, size_t count)
{
auto bss = reinterpret_cast<BaseSequentialStream *>(sdud);
return streamRead(bss, static_cast<uint8_t *>(buffer), count);
}
size_t usbserial_write(const void *buffer, size_t count)
{
auto bss = reinterpret_cast<BaseSequentialStream *>(sdud);
return streamWrite(bss, static_cast<const uint8_t *>(buffer), count);
void init()
{
palSetPadMode(GPIOA, 11, PAL_MODE_ALTERNATE(10));
palSetPadMode(GPIOA, 12, PAL_MODE_ALTERNATE(10));
sduObjectInit(sdud);
sduStart(sdud, &serusbcfg);
// Reconnect bus so device can re-enumerate on reset
usbDisconnectBus(serusbcfg.usbp);
chThdSleepMilliseconds(1500);
usbStart(serusbcfg.usbp, &usbcfg);
usbConnectBus(serusbcfg.usbp);
}
bool is_active()
{
return sdud->config->usbp->state == USB_ACTIVE;
}
size_t read(void *buffer, size_t count)
{
auto bss = reinterpret_cast<BaseSequentialStream *>(sdud);
return streamRead(bss, static_cast<uint8_t *>(buffer), count);
}
size_t write(const void *buffer, size_t count)
{
auto bss = reinterpret_cast<BaseSequentialStream *>(sdud);
return streamWrite(bss, static_cast<const uint8_t *>(buffer), count);
}
}

@ -14,10 +14,14 @@
#include "hal.h"
void usbserial_init();
bool usbserial_is_active();
size_t usbserial_read(void *buffer, size_t count);
size_t usbserial_write(const void *buffer, size_t count);
namespace usbserial
{
void init();
bool is_active();
size_t read(void *buffer, size_t count);
size_t write(const void *buffer, size_t count);
}
#endif // STMDSP_USBSERIAL_HPP_

Loading…
Cancel
Save