summaryrefslogtreecommitdiff
path: root/digital/avr/modules/motor/output/pwm_mp/output_pwm_mp.avr.c
diff options
context:
space:
mode:
Diffstat (limited to 'digital/avr/modules/motor/output/pwm_mp/output_pwm_mp.avr.c')
-rw-r--r--digital/avr/modules/motor/output/pwm_mp/output_pwm_mp.avr.c165
1 files changed, 165 insertions, 0 deletions
diff --git a/digital/avr/modules/motor/output/pwm_mp/output_pwm_mp.avr.c b/digital/avr/modules/motor/output/pwm_mp/output_pwm_mp.avr.c
new file mode 100644
index 00000000..4e644da9
--- /dev/null
+++ b/digital/avr/modules/motor/output/pwm_mp/output_pwm_mp.avr.c
@@ -0,0 +1,165 @@
+/* output_pwm_mp.avr.c */
+/* motor - Motor control module. {{{
+ *
+ * Copyright (C) 2011 Nicolas Schodet
+ *
+ * APBTeam:
+ * Web: http://apbteam.org/
+ * Email: team AT apbteam DOT org
+ *
+ * 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 2 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * }}} */
+#include "common.h"
+#include "output_pwm_mp.h"
+
+#include "modules/spi/spi.h"
+#include "io.h"
+
+/** Define the maximum PWM value for motor power.
+ * This value is lowered until the bug relatives to maximum value is fixed
+ * (rounding after shifting bug). */
+#define OUTPUT_PWM_MP_MAX 0x3f0
+
+/* Test given configuration. */
+#if AC_OUTPUT_PWM_MP_NB != 2 && AC_OUTPUT_PWM_MP_NB != 4
+# error "motor/output/pwm_mp: unsupported configuration"
+#endif
+
+/* Define test macro. */
+#define IF_MP(mp) (AC_OUTPUT_PWM_MP_NB >= ((mp) + 1) * 2)
+
+/** Output information. */
+struct output_pwm_mp_t
+{
+ /** Associated output state. */
+ struct output_t *output;
+};
+typedef struct output_pwm_mp_t output_pwm_mp_t;
+
+/** Global output information. */
+output_pwm_mp_t output_pwm_mp[AC_OUTPUT_PWM_MP_NB];
+
+/** Global enable flag. */
+uint8_t output_pwm_mp_go;
+
+static void
+output_pwm_mp_update_single (int16_t value1, int16_t value2);
+
+/** Initialize hardware, to be done once. */
+static void
+output_pwm_mp_init_hardware (void)
+{
+ static uint8_t inited;
+ if (!inited)
+ {
+#if IF_MP (0) && SPI0_DRIVER != SPI_DRIVER_HARD
+ /* This is done in spi_init for hardware driver. */
+ IO_SET (AC_OUTPUT_PWM_MP_SPI_SS_IO_0);
+ IO_OUTPUT (AC_OUTPUT_PWM_MP_SPI_SS_IO_0);
+#endif
+#if IF_MP (1)
+ IO_SET (AC_OUTPUT_PWM_MP_SPI_SS_IO_1);
+ IO_OUTPUT (AC_OUTPUT_PWM_MP_SPI_SS_IO_1);
+#endif
+ /* Initialise SPI. */
+ spi_init (SPI_MASTER, SPI_CPOL_FALLING | SPI_CPHA_SETUP,
+ SPI_MSB_FIRST, SPI_FOSC_DIV16);
+ /* Reset PWM values at reset. */
+#if IF_MP (0)
+ IO_CLR (AC_OUTPUT_PWM_MP_SPI_SS_IO_0);
+ output_pwm_mp_update_single (0, 0);
+ IO_SET (AC_OUTPUT_PWM_MP_SPI_SS_IO_0);
+#endif
+#if IF_MP (1)
+ IO_CLR (AC_OUTPUT_PWM_MP_SPI_SS_IO_1);
+ output_pwm_mp_update_single (0, 0);
+ IO_SET (AC_OUTPUT_PWM_MP_SPI_SS_IO_1);
+#endif
+ /* Done. */
+ inited = 1;
+ }
+}
+
+void
+output_pwm_mp_init (uint8_t index, output_t *output)
+{
+ /* Need initialized hardware. */
+ output_pwm_mp_init_hardware ();
+ /* Keep output structure for future usage. */
+ output_pwm_mp[index].output = output;
+ /* Reduce maximum output if needed. */
+ if (output->max > OUTPUT_PWM_MP_MAX)
+ output->max = OUTPUT_PWM_MP_MAX;
+}
+
+/** Transmit value to currently selected slave. */
+static void
+output_pwm_mp_update_single (int16_t value1, int16_t value2)
+{
+ uint8_t v;
+ uint8_t cks;
+ /* Convert to 12 bits. */
+ int16_t pwm1c = value1 << 1;
+ int16_t pwm2c = value2 << 1;
+ /* Send, computing checksum on the way. */
+ cks = 0x42;
+ v = ((pwm1c >> 4) & 0xf0) | ((pwm2c >> 8) & 0x0f);
+ spi_send (v);
+ cks ^= v;
+ v = pwm1c;
+ spi_send (v);
+ cks ^= v;
+ v = pwm2c;
+ spi_send (v);
+ cks ^= v;
+ spi_send (cks);
+}
+
+void
+output_pwm_mp_update (void)
+{
+ uint8_t i;
+ /* Activate output at first non zero value. */
+ if (!output_pwm_mp_go)
+ {
+ for (i = 0; i < AC_OUTPUT_PWM_MP_NB; i++)
+ if (output_pwm_mp[i].output->cur)
+ output_pwm_mp_go = 1;
+ }
+ /* Update each output. */
+ if (output_pwm_mp_go)
+ {
+#if IF_MP (0)
+ /* Slave select. */
+ IO_CLR (AC_OUTPUT_PWM_MP_SPI_SS_IO_0);
+ /* Transmit values. */
+ output_pwm_mp_update_single (output_pwm_mp[0].output->cur,
+ output_pwm_mp[1].output->cur);
+ /* Slave deselect. */
+ IO_SET (AC_OUTPUT_PWM_MP_SPI_SS_IO_0);
+#endif
+#if IF_MP (1)
+ /* Slave select. */
+ IO_CLR (AC_OUTPUT_PWM_MP_SPI_SS_IO_1);
+ /* Transmit values. */
+ output_pwm_mp_update_single (output_pwm_mp[2].output->cur,
+ output_pwm_mp[3].output->cur);
+ /* Slave deselect. */
+ IO_SET (AC_OUTPUT_PWM_MP_SPI_SS_IO_1);
+#endif
+ }
+}
+