Browse Source

All atsamx70 blocks working.

Systick trigger working.
New deadzone block.
jeroen
Jeroen Vreeken 3 years ago
parent
commit
30c6d3bd72
30 changed files with 1307 additions and 24 deletions
  1. +9
    -0
      build.mk
  2. +1
    -0
      buildflags.mk.in
  3. +2
    -0
      common/log/log_std.c
  4. +21
    -0
      configure.ac
  5. +2
    -0
      controller/atsamx70/Makefile
  6. +117
    -0
      controller/atsamx70/block_atsamx70_afec.c
  7. +109
    -0
      controller/atsamx70/block_atsamx70_pio_in.c
  8. +110
    -0
      controller/atsamx70/block_atsamx70_pio_out.c
  9. +192
    -0
      controller/atsamx70/block_atsamx70_pwm.c
  10. +241
    -0
      controller/atsamx70/block_atsamx70_tc.c
  11. +28
    -0
      controller/atsamx70/build.mk
  12. +147
    -0
      controller/block/block_deadzone.c
  13. +33
    -12
      controller/block/block_debug.c
  14. +92
    -0
      controller/block/block_debug_bool.c
  15. +79
    -0
      controller/block/block_debug_sint32.c
  16. +1
    -1
      controller/block/block_decoder_uint32_bool.c
  17. +2
    -2
      controller/block/block_gain_ratio_abs.c
  18. +2
    -0
      controller/block/block_value.c
  19. +3
    -0
      controller/block/build.mk
  20. +3
    -0
      controller/build.mk
  21. +1
    -1
      controller/controller/build.mk
  22. +5
    -0
      controller/controller/controller_block.h
  23. +13
    -0
      controller/controller/controller_lib.h
  24. +13
    -1
      controller/controller/controller_lib_static.c
  25. +1
    -1
      controller/controller/controller_load.c
  26. +1
    -1
      controller/controller/controller_sample.c
  27. +4
    -0
      controller/controller/controller_trigger.h
  28. +61
    -0
      controller/ctrl_embedded.ctrl
  29. +4
    -1
      controller/dt_ctrl.c
  30. +10
    -4
      controller/trigger/trigger_systick.c

+ 9
- 0
build.mk View File

@ -27,6 +27,8 @@ endif
ifdef HOSTSYS
CC=${HOSTSYS}-gcc
LD=${HOSTSYS}-ld
OBJCOPY=${HOSTSYS}-objcopy
OBJDUMP=${HOSTSYS}-objdump
LIBTOOL=${HOSTSYS}-libtool
CONF_HOST=--host=${HOSTSYS}
HW=$(HOSTSYS)
@ -101,3 +103,10 @@ endef
%.dtbo: %.dts
@echo " DTCo $<"
@dtc -I dts $< -O dtb -o $@
%.hex: %
$(OBJCOPY) --strip-debug --strip-unneeded $? -O ihex $?.hex
%.asm: %
$(OBJDUMP) -D $? > $?.asm

+ 1
- 0
buildflags.mk.in View File

@ -10,6 +10,7 @@ BUILD_CONSOLE_J2000_INDI=@BUILD_CONSOLE_J2000_INDI@
BUILD_ETHERCAT=@BUILD_ETHERCAT@
BUILD_VESP=@BUILD_VESP@
BUILD_AM335X=@BUILD_AM335X@
BUILD_ATSAMX70=@BUILD_ATSAMX70@
BUILD_LINUX_JOYSTICK=@BUILD_LINUX_JOYSTICK@
BUILD_TEST=@BUILD_TEST@


+ 2
- 0
common/log/log_std.c View File

@ -69,6 +69,8 @@ void log_send(enum log_type type, char *fmt, ...)
va_start(ap, fmt);
vprintf(fmt, ap);
va_end(ap);
printf("\n");
}


+ 21
- 0
configure.ac View File

@ -131,6 +131,7 @@ AC_CHECK_HEADER(semaphore.h,[HAVE_SEMAPHORE=1],[HAVE_SEMAPHORE=0])
AC_CHECK_HEADER(dlfcn.h,[HAVE_DYNAMICLINKING=1],[HAVE_DYNAMICLINKING=0])
AC_CHECK_HEADER(sysclk.h,[HAVE_SYSTICK=1],[HAVE_SYSTICK=0])
AC_CHECK_HEADER(samx70.h,[HAVE_ATSAMX70=1],[HAVE_ATSAMX70=0])
#######################################################################
#
@ -227,6 +228,14 @@ AS_IF([test "$HAVE_SYSTICK" = "1"],
[AC_SUBST(CFLAGS_SYSTICK,["-DHAVE_SYSTICK -D_POSIX_TIMERS"])],
[AC_SUBST(CFLAGS_SYSTICK,[""])])
AS_IF([test "$HAVE_ATSAMX70" = "1"],
[AC_SUBST(BUILD_ATSAMX70,["yes"])],
[AC_SUBST(BUILD_ATSAMX70,[""])])
AS_IF([test "$HAVE_ATSAMX70" = "1"],
[AC_SUBST(CFLAGS_ATSAMX70,["-DHAVE_ATSAMX70"])],
[AC_SUBST(CFLAGS_ATSAMX70,[""])])
#######################################################################
#
# Output
@ -279,6 +288,18 @@ AS_IF([test "$BUILD_AM335X" != ""],
AC_MSG_NOTICE([ am335x: yes]),
AC_MSG_NOTICE([ am335x: no]))
AS_IF([test "$BUILD_ATSAMX70" != ""],
AC_MSG_NOTICE([ atsamx70: yes]),
AC_MSG_NOTICE([ atsamx70: no]))
AS_IF([test "$BUILD_SYSTICK" != ""],
AC_MSG_NOTICE([ systick: yes]),
AC_MSG_NOTICE([ systick: no]))
AS_IF([test "$BUILD_EMBEDDED" != ""],
AC_MSG_NOTICE([ embedded: yes]),
AC_MSG_NOTICE([ embedded: no]))
AS_IF([test "$BUILD_TEST" != ""],
AC_MSG_NOTICE([ test: yes]),
AC_MSG_NOTICE([ test: no]))

+ 2
- 0
controller/atsamx70/Makefile View File

@ -0,0 +1,2 @@
all:
@$(MAKE) --no-print-directory -C ../.. targets_controller/atsamx70

+ 117
- 0
controller/atsamx70/block_atsamx70_afec.c View File

@ -0,0 +1,117 @@
/*
Copyright Jeroen Vreeken (jeroen@vreeken.net), 2018
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <samx70.h>
#include <afec.h>
#include <pio/samx70.h>
#include <ioport.h>
#include <controller/controller_block.h>
#include <log/log.h>
struct controller_block_private {
float value;
uint32_t afecnr;
uint32_t channel;
float factor;
};
static void afec_calculate(struct controller_block *afec)
{
struct controller_block_private *priv = afec->private;
int16_t data = afec_read_conversion_data(priv->afecnr, priv->channel);
float value = data * priv->factor;
priv->value = value;
}
static struct controller_block_outterm_list outterms[] = {
{ "value", CONTROLLER_BLOCK_TERM_FLOAT, offsetof(struct controller_block_private, value) },
{ NULL },
};
static struct controller_block * block_atsamx70_afec_create(char *name, int argc, va_list ap)
{
struct controller_block *afec;
int afec_nr;
afec_nr = va_arg(ap, int);
if (afec_nr < 0 || afec_nr > 1) {
log_send(LOG_T_ERROR, "%s: afec%d is not valid. (valid: 0-1)",
name, afec_nr);
return NULL;
}
if (!(afec = controller_block_alloc("atsamx70_afec", name, sizeof(struct controller_block_private))))
goto err_alloc;
if (controller_block_outterm_list_init(afec, outterms))
goto err_outterm;
afec->calculate = afec_calculate;
uint32_t pin;
switch (afec_nr) {
case 0:
afec->private->afecnr = AFEC0;
afec->private->channel = 0;
pin = PIO_PD30_IDX;
break;
case 1:
afec->private->afecnr = AFEC1;
afec->private->channel = 1;
pin = PIO_PC13_IDX;
break;
}
afec->private->factor = 1.0 / 2048.0;
ioport_init();
ioport_disable_pin(pin);
afec_init(afec->private->afecnr,
AFEC_MR_FREERUN | AFEC_MR_PRESCAL((sysclk_get_peripheral_hz()+AFEC_FMAX-1)/AFEC_FMAX),
AFEC_EMR_RES_16 | AFEC_EMR_STM_SINGLE | AFEC_EMR_SIGNMODE_SIGNED);
afec_channel_set_offset(afec->private->afecnr, 0, (AFEC_ACR_AOFF_MAX+1)/2);
afec_channel_set_gain(afec->private->afecnr, 0, 0); // set gain to 1 (value 0)
afec_channel_enable(afec->private->afecnr, afec_nr);
if (controller_block_add(afec))
goto err_add;
return afec;
err_add:
err_outterm:
controller_block_free(afec);
err_alloc:
return NULL;
}
BLOCK_CREATE(atsamx70_afec) = {
.create = block_atsamx70_afec_create,
.args = { "int", NULL },
};

+ 109
- 0
controller/atsamx70/block_atsamx70_pio_in.c View File

@ -0,0 +1,109 @@
/*
Copyright Jeroen Vreeken (jeroen@vreeken.net), 2018
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <samx70.h>
#include <pio/samx70.h>
#include <ioport.h>
#include <controller/controller_block.h>
#include <log/log.h>
struct controller_block_private {
bool value;
ioport_pin_t pin;
};
static void pio_in_calculate(struct controller_block *pio)
{
struct controller_block_private *priv = pio->private;
priv->value = ioport_get_pin_level(priv->pin);
}
static struct controller_block_outterm_list outterms[] = {
{ "value", CONTROLLER_BLOCK_TERM_BOOL, offsetof(struct controller_block_private, value) },
{ NULL },
};
static struct controller_block * block_atsamx70_pio_in_create(char *name, int argc, va_list ap)
{
struct controller_block *pio;
int pio_nr;
int pin_nr;
pio_nr = va_arg(ap, int);
if (pio_nr < 0 || pio_nr > 4) {
log_send(LOG_T_ERROR, "%s: pio%d is not valid. (valid: 0-4)", name, pio_nr);
return NULL;
}
pin_nr = va_arg(ap, int);
if (pin_nr < 0 || pin_nr > 31) {
log_send(LOG_T_ERROR, "%s: pin%d is not valid. (valid: 0-31)", name, pin_nr);
}
if (!(pio = controller_block_alloc("atsamx70_pio_in", name, sizeof(struct controller_block_private))))
goto err_alloc;
if (controller_block_outterm_list_init(pio, outterms))
goto err_outterm;
pio->calculate = pio_in_calculate;
switch (pio_nr) {
case 0:
pio->private->pin = PIO_PA_IDX;
break;
case 1:
pio->private->pin = PIO_PB_IDX;
break;
case 2:
pio->private->pin = PIO_PC_IDX;
break;
case 3:
pio->private->pin = PIO_PD_IDX;
break;
case 4:
pio->private->pin = PIO_PE_IDX;
break;
}
pio->private->pin |= pin_nr;
ioport_init();
ioport_enable_pin(pio->private->pin);
ioport_set_pin_dir(pio->private->pin, IOPORT_DIR_INPUT);
if (controller_block_add(pio))
goto err_add;
return pio;
err_add:
err_outterm:
controller_block_free(pio);
err_alloc:
return NULL;
}
BLOCK_CREATE(atsamx70_pio_in) = {
.create = block_atsamx70_pio_in_create,
.args = { "int,int", NULL },
};

+ 110
- 0
controller/atsamx70/block_atsamx70_pio_out.c View File

@ -0,0 +1,110 @@
/*
Copyright Jeroen Vreeken (jeroen@vreeken.net), 2018
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <samx70.h>
#include <pio/samx70.h>
#include <ioport.h>
#include <controller/controller_block.h>
#include <log/log.h>
struct controller_block_private {
bool *value;
ioport_pin_t pin;
};
static void pio_out_calculate(struct controller_block *pio)
{
struct controller_block_private *priv = pio->private;
bool value = *priv->value;
ioport_set_pin_level(priv->pin, value);
}
static struct controller_block_interm_list interms[] = {
{ "value", CONTROLLER_BLOCK_TERM_BOOL, offsetof(struct controller_block_private, value) },
{ NULL },
};
static struct controller_block * block_atsamx70_pio_out_create(char *name, int argc, va_list ap)
{
struct controller_block *pio;
int pio_nr;
int pin_nr;
pio_nr = va_arg(ap, int);
if (pio_nr < 0 || pio_nr > 4) {
log_send(LOG_T_ERROR, "%s: pio%d is not valid. (valid: 0-4)", name, pio_nr);
return NULL;
}
pin_nr = va_arg(ap, int);
if (pin_nr < 0 || pin_nr > 31) {
log_send(LOG_T_ERROR, "%s: pin%d is not valid. (valid: 0-31)", name, pin_nr);
}
if (!(pio = controller_block_alloc("atsamx70_pio_out", name, sizeof(struct controller_block_private))))
goto err_alloc;
if (controller_block_interm_list_init(pio, interms))
goto err_interm;
pio->calculate = pio_out_calculate;
switch (pio_nr) {
case 0:
pio->private->pin = PIO_PA_IDX;
break;
case 1:
pio->private->pin = PIO_PB_IDX;
break;
case 2:
pio->private->pin = PIO_PC_IDX;
break;
case 3:
pio->private->pin = PIO_PD_IDX;
break;
case 4:
pio->private->pin = PIO_PE_IDX;
break;
}
pio->private->pin |= pin_nr;
ioport_init();
ioport_enable_pin(pio->private->pin);
ioport_set_pin_dir(pio->private->pin, IOPORT_DIR_OUTPUT);
if (controller_block_add(pio))
goto err_add;
return pio;
err_add:
err_interm:
controller_block_free(pio);
err_alloc:
return NULL;
}
BLOCK_CREATE(atsamx70_pio_out) = {
.create = block_atsamx70_pio_out_create,
.args = { "int,int", NULL },
};

+ 192
- 0
controller/atsamx70/block_atsamx70_pwm.c View File

@ -0,0 +1,192 @@
/*
Copyright Jeroen Vreeken (jeroen@vreeken.net), 2018
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <samx70.h>
#include <pwm.h>
#include <pio/samx70.h>
#include <ioport.h>
#include <controller/controller_block.h>
#include <log/log.h>
struct controller_block_private {
float *in;
int period;
uint32_t pwm;
int ch_nr;
uint32_t outputh;
uint32_t outputl;
};
static void pwm_calculate(struct controller_block *pwm)
{
struct controller_block_private *priv = pwm->private;
uint32_t pw = priv->pwm;
float in = *priv->in;
int period = priv->period;
uint32_t outputl = priv->outputl;
uint32_t outputh = priv->outputh;
int ch_nr = priv->ch_nr;
int duty = in * period;
uint32_t dty = abs(duty);
/* Make sure we generate negative pulses for capacitor loading */
if (dty >= period) {
dty--;
}
if (duty > 0) {
pwm_output_selection_set(pw, outputl);
pwm_channel_duty_cycle_update_set(pw, ch_nr, dty);
pwm_output_selection_clear_update(pw, outputh);
} else if (duty < 0) {
pwm_output_selection_set(pw, outputh);
pwm_channel_duty_cycle_update_set(pw, ch_nr, dty);
pwm_output_selection_clear_update(pw, outputl);
} else {
pwm_output_selection_set(pw, outputh | outputl);
pwm_channel_duty_cycle_update_set(pw, ch_nr, dty);
}
pwm_sync_update(pw);
}
static struct controller_block_interm_list interms[] = {
{ "in", CONTROLLER_BLOCK_TERM_FLOAT, offsetof(struct controller_block_private, in) },
{ NULL },
};
static struct controller_block * block_atsamx70_pwm_create(char *name, int argc, va_list ap)
{
struct controller_block *pwm;
int pwm_nr;
int ch_nr;
double frequency;
pwm_nr = va_arg(ap, int);
if (pwm_nr < 0 || pwm_nr > 1) {
log_send(LOG_T_ERROR, "%s: pwm%d is not valid. (valid: 0-1)",
name, pwm_nr);
return NULL;
}
ch_nr = va_arg(ap, int);
if (ch_nr < 0 || ch_nr > 1) {
log_send(LOG_T_ERROR, "%s: channel %d is not valid. (valid: 0-3)",
name, ch_nr);
return NULL;
}
double fclock = sysclk_get_peripheral_hz();
frequency = va_arg(ap, double);
int period = fclock / frequency;
log_send(LOG_T_DEBUG, "%s: Frequency: %fHz, period: %d (%fHz)", name,
frequency, period, fclock / period);
if (!(pwm = controller_block_alloc("atsamx70_pwm", name, sizeof(struct controller_block_private))))
goto err_alloc;
if (controller_block_interm_list_init(pwm, interms))
goto err_interm;
pwm->calculate = pwm_calculate;
pwm->private->ch_nr = ch_nr;
pwm->private->period = period;
switch (pwm_nr) {
case 0:
pwm->private->pwm = PWM0;
break;
case 1:
pwm->private->pwm = PWM1;
break;
}
pwm_init(pwm->private->pwm);
pwm_disable(pwm->private->pwm, ch_nr);
uint32_t oov = pwm_output_override_get(pwm->private->pwm);
switch (ch_nr) {
case 0:
oov &= ~(PWM_OOV_OOVL0 | PWM_OOV_OOVH0);
pwm->private->outputh = PWM_OS_OSL0;
pwm->private->outputl = PWM_OS_OSH0;
ioport_disable_pin(PIO_PD20_IDX);
ioport_set_pin_mode(PIO_PD20_IDX, IOPORT_MODE_MUX_A);
ioport_set_pin_dir(PIO_PD20_IDX, IOPORT_DIR_OUTPUT);
ioport_disable_pin(PIO_PA19_IDX);
ioport_set_pin_mode(PIO_PA19_IDX, IOPORT_MODE_MUX_B);
ioport_set_pin_dir(PIO_PA19_IDX, IOPORT_DIR_OUTPUT);
break;
case 1:
oov &= ~(PWM_OOV_OOVL1 | PWM_OOV_OOVH1);
pwm->private->outputh = PWM_OS_OSL1;
pwm->private->outputl = PWM_OS_OSH1;
break;
case 2:
oov &= ~(PWM_OOV_OOVL2 | PWM_OOV_OOVH2);
pwm->private->outputh = PWM_OS_OSL0;
pwm->private->outputl = PWM_OS_OSH2;
break;
case 3:
oov &= ~(PWM_OOV_OOVL3 | PWM_OOV_OOVH3);
pwm->private->outputh = PWM_OS_OSL3;
pwm->private->outputl = PWM_OS_OSH3;
break;
}
pwm_output_override_set(pwm->private->pwm, oov);
pwm_output_selection_set_update(pwm->private->pwm, pwm->private->outputh | pwm->private->outputl);
pwm_sync_mode_set(pwm->private->pwm,
PWM_SCM_SYNC0 | PWM_SCM_SYNC1 | PWM_SCM_SYNC2 | PWM_SCM_SYNC3);
pwm_channel_mode_set(pwm->private->pwm, ch_nr, PWM_CMR_CPOL | PWM_CMR_DPOLI | PWM_CMR_DTLI);
pwm_channel_period_set(pwm->private->pwm, ch_nr, period);
pwm_channel_duty_cycle_update_set(pwm->private->pwm, ch_nr, 0);
pwm_channel_dead_time_set(pwm->private->pwm, ch_nr, 0);
pwm_sync_update(pwm->private->pwm);
pwm_enable(pwm->private->pwm, ch_nr);
if (controller_block_add(pwm))
goto err_add;
return pwm;
err_add:
err_interm:
controller_block_free(pwm);
err_alloc:
return NULL;
}
BLOCK_CREATE(atsamx70_pwm) = {
.create = block_atsamx70_pwm_create,
.args = { "int,int,double", NULL },
};

+ 241
- 0
controller/atsamx70/block_atsamx70_tc.c View File

@ -0,0 +1,241 @@
/*
Copyright Jeroen Vreeken (jeroen@vreeken.net), 2018
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <samx70.h>
#include <tc.h>
#include <pio/samx70.h>
#include <ioport.h>
#include <controller/controller_block.h>
#include <controller/controller_time.h>
#include <log/log.h>
struct controller_block_private {
float position;
float speed;
bool homed;
bool *reset;
uint16_t prevcnt0;
int rev;
float speedfac;
float posfac;
uint32_t tcn;
};
static void tc_calculate(struct controller_block *tc)
{
struct controller_block_private *priv = tc->private;
uint16_t cnt0;
int16_t cnt1;
uint16_t prevcnt0 = priv->prevcnt0;
float speed;
float position;
int rev = priv->rev;
cnt0 = tc_get_cv(priv->tcn, 0);
cnt1 = tc_get_cv(priv->tcn, 1);
uint32_t qisr = tc_get_qisr(priv->tcn);
priv->homed |= qisr & TC_QISR_IDX;
priv->homed &= !(*priv->reset);
if (cnt0 > rev)
cnt0 += rev;
int16_t diff = cnt0 - prevcnt0;
if (diff > rev/2)
diff -= rev;
if (diff < -rev/2)
diff += rev;
speed = diff * priv->speedfac;
position = (cnt1 * rev + cnt0) * priv->posfac;
priv->prevcnt0 = cnt0;
priv->speed = speed;
priv->position = position;
}
static struct controller_block_outterm_list outterms[] = {
{ "position", CONTROLLER_BLOCK_TERM_FLOAT, offsetof(struct controller_block_private, position) },
{ "homed", CONTROLLER_BLOCK_TERM_BOOL, offsetof(struct controller_block_private, homed) },
{ "speed", CONTROLLER_BLOCK_TERM_FLOAT, offsetof(struct controller_block_private, speed) },
{ NULL },
};
static struct controller_block_interm_list interms[] = {
{ "reset", CONTROLLER_BLOCK_TERM_BOOL, offsetof(struct controller_block_private, reset) },
{ NULL }
};
static struct controller_block * block_atsamx70_tc_create(char *name, int argc, va_list ap)
{
struct controller_block *tc;
int tc_nr;
int rev;
int inverted;
tc_nr = va_arg(ap, int);
if (tc_nr < 0 || tc_nr > 3) {
log_send(LOG_T_ERROR, "%s: tc%d is not valid. (valid: 0-3)",
name, tc_nr);
return NULL;
}
rev = va_arg(ap, int);
inverted = va_arg(ap, int);
if (!(tc = controller_block_alloc("atsamx70_tc", name, sizeof(struct controller_block_private))))
goto err_alloc;
if (controller_block_outterm_list_init(tc, outterms))
goto err_outterm;
if (controller_block_interm_list_init(tc, interms))
goto err_interm;
tc->calculate = tc_calculate;
uint32_t pa, pb, pi;
uint32_t fa, fb, fi;
switch (tc_nr) {
case 0:
tc->private->tcn = TC0;
pa = PIO_TIOA0_IDX;
pb = PIO_TIOB0_IDX;
pi = PIO_TIOB1_IDX;
fa = IOPORT_MODE_TIOA0;
fb = IOPORT_MODE_TIOB0;
fi = IOPORT_MODE_TIOB1;
break;
case 1:
tc->private->tcn = TC1;
pa = PIO_TIOA3_IDX;
pb = PIO_TIOB3_IDX;
pi = PIO_TIOB4_IDX;
fa = IOPORT_MODE_TIOA3;
fb = IOPORT_MODE_TIOB3;
fi = IOPORT_MODE_TIOB4;
break;
case 2:
tc->private->tcn = TC2;
pa = PIO_TIOA6_IDX;
pb = PIO_TIOB6_IDX;
pi = PIO_TIOB7_IDX;
fa = IOPORT_MODE_TIOA6;
fb = IOPORT_MODE_TIOB6;
fi = IOPORT_MODE_TIOB7;
break;
case 3:
tc->private->tcn = TC3;
pa = PIO_TIOA9_IDX;
pb = PIO_TIOB9_IDX;
pi = PIO_TIOB10_IDX;
fa = IOPORT_MODE_TIOA9;
fb = IOPORT_MODE_TIOB9;
fi = IOPORT_MODE_TIOB10;
break;
}
tc->private->rev = rev * 4;
tc->private->homed = false;
ioport_init();
ioport_disable_pin(pa);
ioport_set_pin_mode(pa, fa);
ioport_set_pin_dir(pa, IOPORT_DIR_INPUT);
ioport_disable_pin(pb);
ioport_set_pin_mode(pb, fb);
ioport_set_pin_dir(pb, IOPORT_DIR_INPUT);
ioport_disable_pin(pi);
ioport_set_pin_mode(pi, fi);
ioport_set_pin_dir(pi, IOPORT_DIR_INPUT);
/*
When writing a 0 to TC_BMR.QDEN, the QDEC is bypassed and the IO pins are
directly routed to the timer counter function.
When TC_BMR.POSEN is set, the motor axis position is processed on channel 0
(by means of the PHA, PHB edge detections) and the number of motor revolutions
are recorded on channel 1 if the IDX signal is provided on the TIOB1 input.
If no IDX signal is available, the internal counter can be cleared for each
revolution if the number of counts per revolution is configured in TC_RC0.RC
and the TC_CMR.CPCTRG bit is written to 1.
The position measurement can be read in the TC_CV0 register and the rotation
measurement can be read in the TC_CV1 register.
Channel 0 and 1 must be configured in Capture mode (TC_CMR0.WAVE = 0).
Rising edge must be selected as the External Trigger Edge (TC_CMR.ETRGEDG = 0x01)
and TIOAx must be selected as the External Trigger (TC_CMR.ABETRG = 0x1).
The process must be started by configuring TC_CCR.CLKEN and TC_CCR.SWTRG.
In parallel, the number of edges are accumulated on TC channel 0 and
can be read on the TC_CV0 register.
Therefore, the accurate position can be read on both TC_CV registers and
concatenated to form a 32-bit word.
The TC channel 0 is cleared for each increment of IDX count value.
Depending on the quadrature signals, the direction is decoded
and allows to count up or down in TC channels 0 and 1.
The direction status is reported on TC_QISR.
*/
tc_init(tc->private->tcn, TC_CH0,
TC_CMR_ETRGEDG_RISING | TC_CMR_ABETRG_A | TC_CMR_TCCLKS_XC0 | TC_CMR_CPCTRG,
0);
tc_write_rc(tc->private->tcn, TC_CH0, rev * 4);
tc_init(tc->private->tcn, TC_CH1,
TC_CMR_TCCLKS_XC0,
0);
tc_init(tc->private->tcn, TC_CH2, 0, 0);
tc_block_mode_set(tc->private->tcn, TC_BMR_QDEN | TC_BMR_POSEN | TC_BMR_EDGPHA |
(inverted ? (TC_BMR_INVA | TC_BMR_INVB | TC_BMR_INVIDX) : (0)));
tc_start(tc->private->tcn, TC_CH0);
tc_start(tc->private->tcn, TC_CH1);
tc->private->speedfac = (controller_time_period_get(tc->time) * M_PI * 2) * (rev * 4);
tc->private->posfac = (M_PI * 2) / (rev * 4);
if (controller_block_add(tc))
goto err_add;
return tc;
err_add:
err_interm:
err_outterm:
controller_block_free(tc);
err_alloc:
return NULL;
}
BLOCK_CREATE(atsamx70_tc) = {
.create = block_atsamx70_tc_create,
.args = { "int,int,int", NULL },
};

+ 28
- 0
controller/atsamx70/build.mk View File

@ -0,0 +1,28 @@
ATSAMX70_TARGETS := $(LIBDIR)/libatsamx70.la
ATSAMX70_BLOCKS := \
atsamx70_afec \
atsamx70_pio_in \
atsamx70_pio_out \
atsamx70_pwm \
atsamx70_tc
ATSAMX70_SRCS += \
$(addsuffix .c,$(addprefix $(DIR)/block_,$(ATSAMX70_BLOCKS)))
CTRL_BLOCKS += $(ATSAMX70_BLOCKS)
CTRL_BLOCK_LIBS += libatsamx70.la
ATSAMX70_OBJS := $(ATSAMX70_SRCS:.c=.lo)
$(ATSAMX70_OBJS): CFLAGS += -O3 -Wall
$(LIBDIR)/libatsamx70.la_LDFLAGS +=
$(LIBDIR)/libatsamx70.la: $(ATSAMX70_OBJS)
$(LIB_LINK)
TARGETS += $(ATSAMX70_TARGETS)
CLEAN += $(ATSAMX70_TARGETS) $(ATSAMX70_OBJS)
SRCS += $(ATSAMX70_SRCS)

+ 147
- 0
controller/block/block_deadzone.c View File

@ -0,0 +1,147 @@
/*
Copyright Jeroen Vreeken (jeroen@vreeken.net), 2018
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <controller/controller_block.h>
#include <log/log.h>
/*
inputs outputs
nr name nr name
----------------------
| |
---| 0 in 0 out |----
| |
----------------------
*/
struct controller_block_private {
float *input0;
float out;
float deadzone;
float gain;
float intercept;
};
static void deadzone_calculate(struct controller_block *dz)
{
struct controller_block_private *priv = dz->private;
float in = *priv->input0;
float deadzone = priv->deadzone;
float out;
if (in > deadzone) {
out = in - deadzone;
} else if (in < -deadzone) {
out = in + deadzone;
} else {
out = 0.0;
}
out *= priv->gain;
priv->out = out;
}
static void param_set(struct controller_block *dz)
{
struct controller_block_private *priv = dz->private;
/* exception: no intercept */
if (priv->intercept == 0.0) {
priv->gain = 1.0;
} else {
priv->gain = priv->intercept / (priv->intercept - priv->deadzone);
}
}
static int param_set_dz(struct controller_block *dz, char *param, int argc,
va_list val)
{
dz->private->deadzone = fabs(va_arg(val, double));
param_set(dz);
return 0;
}
static int param_set_i(struct controller_block *dz, char *param, int argc,
va_list val)
{
dz->private->intercept = fabs(va_arg(val, double));
param_set(dz);
return 0;
}
static struct controller_block_param_list params[] = {
{ "deadzone", false, param_set_dz, .args = { "double", NULL } },
{ "intercept", false, param_set_i, .args = { "double", NULL } },
{ NULL },
};
static struct controller_block_interm_list interms[] = {
{ "in", CONTROLLER_BLOCK_TERM_FLOAT, offsetof(struct controller_block_private, input0) },
{ NULL }
};
static struct controller_block_outterm_list outterms[] = {
{ "out", CONTROLLER_BLOCK_TERM_FLOAT, offsetof(struct controller_block_private, out) },
{ NULL }
};
static struct controller_block * block_deadzone_create(char *name, int argc, va_list val)
{
struct controller_block *dz;
if (!(dz = controller_block_alloc("deadzone", name, sizeof(struct controller_block_private))))
return NULL;
dz->private->out = 0.0;
dz->private->deadzone = 0.0;
dz->private->intercept = 0.0;
param_set(dz);
if (controller_block_interm_list_init(dz, interms))
goto err_block;
if (controller_block_outterm_list_init(dz, outterms))
goto err_block;
dz->calculate = deadzone_calculate;
if (controller_block_param_list_add(dz, params))
goto err_block;
if (controller_block_add(dz))
goto err_block;
return dz;
err_block:
controller_block_free(dz);
return NULL;
}
BLOCK_CREATE(deadzone) = {
.create = block_deadzone_create,
.args = { NULL },
};

+ 33
- 12
controller/block/block_debug.c View File

@ -1,5 +1,5 @@
/*
Copyright Jeroen Vreeken (pe1rxq@amsat.org), 2007
Copyright Jeroen Vreeken (jeroen@vreeken.net), 2007, 2018
Copyright Stichting C.A. Muller Radioastronomiestation, 2007
This program is free software: you can redistribute it and/or modify
@ -22,6 +22,8 @@
#include <string.h>
#include <controller/controller_block.h>
#include <controller/controller_time.h>
#include <log/log.h>
/*
inputs
@ -34,13 +36,24 @@
struct controller_block_private {
float *in;
int count;
int interval;
};
static void calculate(struct controller_block *debug)
{
fprintf(stderr, "%s.in: %e\n", debug->name, *debug->private->in);
debug->private->count++;
if (debug->private->count >= debug->private->interval) {
log_send(LOG_T_DEBUG, "%s.in: %e", debug->name, *debug->private->in);
debug->private->count = 0;
}
}
static struct controller_block_interm_list interms[] = {
{ "in", CONTROLLER_BLOCK_TERM_FLOAT, offsetof(struct controller_block_private, in) },
{ NULL }
};
struct controller_block * block_debug_create(char *name, int argc, va_list ap)
{
struct controller_block *debug;
@ -48,15 +61,16 @@ struct controller_block * block_debug_create(char *name, int argc, va_list ap)
if (!(debug = controller_block_alloc("debug", name, sizeof(struct controller_block_private))))
return NULL;
debug->inputs = 1;
debug->input = malloc(sizeof(struct controller_block_interm) * 1);
if (!debug->input)
goto err_name;
debug->input[0].name = "in";
debug->input[0].type = CONTROLLER_BLOCK_TERM_FLOAT;
debug->input[0].value.f = &debug->private->in;
debug->input[0].ghostof = NULL;
if (controller_block_interm_list_init(debug, interms))
goto err_block;
double chz = controller_time_frequency_get(debug->time);
double hz = chz;
if (argc > 0)
hz = va_arg(ap, double);
debug->private->interval = chz / hz;
debug->outputs = 0;
debug->output = NULL;
@ -68,12 +82,19 @@ struct controller_block * block_debug_create(char *name, int argc, va_list ap)
return debug;
err_add:
err_name:
err_block:
controller_block_free(debug);
return NULL;
}
struct controller_block * block_debug_float_create(char *name, int argc, va_list ap) __attribute__ ((alias("block_debug_create")));
BLOCK_CREATE(debug) = {
.create = block_debug_create,
.args = { NULL },
.args = { "", "double", NULL },
};
BLOCK_CREATE(debug_float) = {
.create = block_debug_float_create,
.args = { "", "double", NULL },
};

+ 92
- 0
controller/block/block_debug_bool.c View File

@ -0,0 +1,92 @@
/*
Copyright Jeroen Vreeken (pe1rxq@amsat.org), 2007, 2018
Copyright Stichting C.A. Muller Radioastronomiestation, 2007
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
#include <controller/controller_block.h>
#include <controller/controller_time.h>
/*
inputs
nr name
----------------
---| 0 in |
----------------
*/
struct controller_block_private {
bool *in;
int count;
int interval;
};
static void calculate(struct controller_block *debug)
{
debug->private->count++;
if (debug->private->count >= debug->private->interval) {
fprintf(stderr, "%s.in: %s\n", debug->name, *debug->private->in ? "true" : "false");
debug->private->count = 0;
}
}
static struct controller_block_interm_list interms[] = {
{ "in", CONTROLLER_BLOCK_TERM_BOOL, offsetof(struct controller_block_private, in) },
{ NULL }
};
struct controller_block * block_debug_bool_create(char *name, int argc, va_list ap)
{
struct controller_block *debug;
if (!(debug = controller_block_alloc("debug", name, sizeof(struct controller_block_private))))
return NULL;
if (controller_block_interm_list_init(debug, interms))
goto err_block;
double chz = controller_time_frequency_get(debug->time);
double hz = chz;
if (argc > 0)
hz = va_arg(ap, double);
debug->private->interval = chz / hz;
debug->outputs = 0;
debug->output = NULL;
debug->calculate = calculate;
if (controller_block_add(debug))
goto err_add;
return debug;
err_add:
err_block:
controller_block_free(debug);
return NULL;
}
BLOCK_CREATE(debug_bool) = {
.create = block_debug_bool_create,
.args = { "", "double", NULL },
};

+ 79
- 0
controller/block/block_debug_sint32.c View File

@ -0,0 +1,79 @@
/*
Copyright Jeroen Vreeken (pe1rxq@amsat.org), 2007, 2018
Copyright Stichting C.A. Muller Radioastronomiestation, 2007
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
#include <controller/controller_block.h>
#include <log/log.h>
/*
inputs
nr name
----------------
---| 0 in |
----------------
*/
struct controller_block_private {
int32_t *in;
};
static void calculate(struct controller_block *debug)
{
log_send(LOG_T_DEBUG, "%s.in: 0x%"PRIx32" %"PRId32, debug->name, *debug->private->in, *debug->private->in);
}
static struct controller_block_interm_list interms[] = {
{ "in", CONTROLLER_BLOCK_TERM_SINT32, offsetof(struct controller_block_private, in) },
{ NULL }
};
struct controller_block * block_debug_sint32_create(char *name, int argc, va_list ap)
{
struct controller_block *debug;
if (!(debug = controller_block_alloc("debug", name, sizeof(struct controller_block_private))))
return NULL;
if (controller_block_interm_list_init(debug, interms))
goto err_block;
debug->outputs = 0;
debug->output = NULL;
debug->calculate = calculate;
if (controller_block_add(debug))
goto err_add;
return debug;
err_add:
err_block:
controller_block_free(debug);
return NULL;
}
BLOCK_CREATE(debug_sint32) = {
.create = block_debug_sint32_create,
.args = { NULL },
};

+ 1
- 1
controller/block/block_decoder_uint32_bool.c View File

@ -112,7 +112,7 @@ err_out:
return NULL;
}
BLOCK_CREATE(decoder_uint32) = {
BLOCK_CREATE(decoder_uint32_bool) = {
.create = block_decoder_uint32_bool_create,
.args = { "int", NULL },
};

+ 2
- 2
controller/block/block_gain_ratio_abs.c View File

@ -63,7 +63,7 @@ static struct controller_block_outterm_list outterms[] = {
{ NULL }
};
struct controller_block * block_gain_ra_create(char *name, int argc,
struct controller_block * block_gain_ratio_abs_create(char *name, int argc,
va_list ap)
{
struct controller_block *gain;
@ -92,7 +92,7 @@ err_block:
}
BLOCK_CREATE(gain_ratio_abs) = {
.create = block_gain_ra_create,
.create = block_gain_ratio_abs_create,
.args = { NULL },
};

+ 2
- 0
controller/block/block_value.c View File

@ -87,6 +87,8 @@ err_block:
return NULL;
}
static struct controller_block * block_value_create(char *name,
int argc, va_list ap) __attribute__ ((alias("block_value_float_create")));
BLOCK_CREATE(value_float) = {
.create = block_value_float_create,


+ 3
- 0
controller/block/build.mk View File

@ -9,7 +9,10 @@ BLOCKS := \
bridge_pwm \
controller_profile \
counter \
deadzone \
debug \
debug_bool \
debug_sint32 \
decoder_uint32_bool \
ex \
filter_iir \


+ 3
- 0
controller/build.mk View File

@ -24,6 +24,9 @@ endif
ifdef BUILD_AM335X
$(eval $(call SUBDIR,am335x))
endif
ifdef BUILD_ATSAMX70
$(eval $(call SUBDIR,atsamx70))
endif
DT_CTRL_TARGETS += $(DIR)/dt_ctrl


+ 1
- 1
controller/controller/build.mk View File

@ -47,7 +47,7 @@ endif
CONTROLLER_OBJS := $(CONTROLLER_SRCS:.c=.lo)
$(CONTROLLER_OBJS): CFLAGS += -g -Wall
$(CONTROLLER_OBJS): CFLAGS += -O3 -Wall
ifdef BUILD_TCP
$(LIBDIR)/libcontroller.la: libshell.la libcommand.la libtrace.la
$(LIBDIR)/libcontroller.la_LDFLAGS += -lshell -lpthread -lrt -lcommand -ltrace


+ 5
- 0
controller/controller/controller_block.h View File

@ -25,6 +25,8 @@
#include <math.h>
#include <stdarg.h>
#include <controller/controller_lib.h>
// Keep this enum in sync with the list in controller_block_term_type2str() in
// controller_block.c !
enum controller_block_term_type {
@ -254,6 +256,9 @@ struct controller_block_create {
};
#define BLOCK_CREATE(type) \
extern struct controller_block_create block_ ## type ## _create_struct; \
LIB_SYMBOL(block_ ## type ## _create_struct) \
\
struct controller_block_create block_ ## type ## _create_struct __attribute__((used))
#endif

+ 13
- 0
controller/controller/controller_lib.h View File

@ -20,4 +20,17 @@
void *controller_lib_sym(char *symbol_name);
struct controller_lib_symbol {
void *symbol;
char *symbol_name;
};
#define LIB_SYMBOL(name) \
__attribute__ ((section (".static_lib"))) struct controller_lib_symbol controller_lib_ ## name ## _symbol = \
{ \
.symbol = &name, \
.symbol_name = #name, \
};
#endif /*_INCLUDE_CONTROLLER_LIB_H_*/

+ 13
- 1
controller/controller/controller_lib_static.c View File

@ -18,9 +18,21 @@
#include <controller/controller_lib.h>
#include <stdlib.h>
#include <string.h>
extern int __static_lib_start;
extern int __static_lib_end;
void *controller_lib_sym(char *symbol_name)
{
//TODO stub for now
struct controller_lib_symbol *sym_start = (void *)&__static_lib_start;
struct controller_lib_symbol *sym_end = (void *)&__static_lib_end;
struct controller_lib_symbol *sym;
for (sym = sym_start; sym != sym_end; sym++) {
if (!strcmp(sym->symbol_name, symbol_name))
return sym->symbol;
}
return NULL;
}

+ 1
- 1
controller/controller/controller_load.c View File

@ -658,7 +658,7 @@ int controller_load_mem(char *name, char *ctrl, size_t ctrl_size)
yylex_init_extra(&extra, &scanner);
safe_context = controller_block_context_get();
controller_block_context_set("shell");
controller_block_context_set(name);
ret = yyparse(scanner);


+ 1
- 1
controller/controller/controller_sample.c View File

@ -320,7 +320,7 @@ void controller_sample_iteration(controller_trigger_time t_trig)
controller_sample_task_exec();
t_end = timestamp();
controller_sample_latency = t_start - t_trig;
controller_sample_duration_blocks = t_block - t_start;
controller_sample_duration_sample = t_end - t_start;


+ 4
- 0
controller/controller/controller_trigger.h View File

@ -23,6 +23,7 @@
#include <stdarg.h>
#include <time.h>
#include <controller/controller_lib.h>
typedef uint64_t controller_trigger_time;
@ -51,6 +52,9 @@ struct controller_trigger_create {
};
#define TRIGGER_CREATE(type) \
extern struct controller_trigger_create trigger_ ## type ## _create_struct; \
LIB_SYMBOL(trigger_ ## type ## _create_struct) \
\
struct controller_trigger_create trigger_ ## type ## _create_struct __attribute__((used))
#endif

+ 61
- 0
controller/ctrl_embedded.ctrl View File

@ -0,0 +1,61 @@
# embedded ctrl
#
#
set frequency 100
set delay 0.0
trigger {
{ "systick" }
}
blocks ($(frequency), $(delay)) {
# Profiling block, may be commented out.
{ "controller_profile", "profile" }
{ "atsamx70_tc", "counter0", 0, 2500, 0 }
{ "atsamx70_tc", "counter1", 1, 10000, 0 }
{ "atsamx70_afec", "afec0", 0 }
{ "atsamx70_pwm", "pwm0", 0, 0, 10000.0 }
# { "debug_float", "debug_counter0_p", 1.0 }
# { "debug_float", "debug_counter1_p", 1.0 }
# { "debug_bool", "debug_homed0", 1.0 }
# { "debug_bool", "debug_homed1", 1.0 }
# { "debug_float", "debug_counter0_v", 1.0 }
# { "debug_float", "debug_counter1_v", 1.0 }
# { "debug_float", "debug_afec0", 1.0 }
# { "debug_float", "debug_sample", 1.0 }
{ "value_bool", "false" }
{ "value_float", "zero" }
}
blocks (2.0, 0.0) {
{ "atsamx70_pio_out", "blinky_LED", 2, 8 } #PC8
{ "not", "blinky" }
}
alias {
}
links {
# { "profile", "sample", "debug_sample", "in", true }
{ "false", "value", "counter0", "reset", true }
{ "false", "value", "counter1", "reset", true }
# { "counter0", "position", "debug_counter0_p", "in", true }
# { "counter1", "position", "debug_counter1_p", "in", true }
# { "counter0", "speed", "debug_counter0_v", "in", true }
# { "counter1", "speed", "debug_counter1_v", "in", true }
# { "counter0", "homed", "debug_homed0", "in", true }
# { "counter1", "homed", "debug_homed1", "in", true }
# { "afec0", "value", "debug_afec0", "in", true }
{ "afec0", "value", "pwm0", "in", true }
{ "blinky", "output", "blinky", "input", false }
{ "blinky", "output", "blinky_LED", "value", true }
}
params {
}

+ 4
- 1
controller/dt_ctrl.c View File

@ -1,5 +1,5 @@
/*
Copyright Jeroen Vreeken (pe1rxq@amsat.org), 2007 - 2016
Copyright Jeroen Vreeken (pe1rxq@amsat.org), 2007 - 2018
Copyright Stichting C.A. Muller Radioastronomiestation, 2007 - 2013
This program is free software: you can redistribute it and/or modify
@ -92,9 +92,12 @@ int main(int argc, char **argv)
goto err_init;
}
#else
log_send(LOG_T_DEBUG, "Going to load embedded controller file");
controller_load_mem("ctrl_embedded",
&_binary_controller_ctrl_embedded_ctrl_start,
&_binary_controller_ctrl_embedded_ctrl_end - &_binary_controller_ctrl_embedded_ctrl_start);
controller_block_link();
#endif
if (controller_time_process() != 0) {


+ 10
- 4
controller/trigger/trigger_systick.c View File

@ -43,16 +43,22 @@ static controller_trigger_time timestamp(void)
static void sample_systick(void)
{
controller_sample_iteration(timestamp());
controller_trigger_time t_trig = timestamp();
controller_sample_iteration(t_trig);
}