Commit 30c6d3bd authored by Jeroen Vreeken's avatar Jeroen Vreeken
Browse files

All atsamx70 blocks working.

Systick trigger working.
New deadzone block.
parent e1cc8739
......@@ -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
......@@ -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@
......
......@@ -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");
}
......
......@@ -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]))
all:
@$(MAKE) --no-print-directory -C ../.. targets_controller/atsamx70
/*
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 },
};
/*
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 },
};
/*
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 },
};
/*
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 },
};