summaryrefslogtreecommitdiff
path: root/firmware
diff options
context:
space:
mode:
Diffstat (limited to 'firmware')
-rw-r--r--firmware/drivers/i2s.c61
-rw-r--r--firmware/drivers/i2s.h71
-rw-r--r--firmware/test/i2s/Makefile8
-rw-r--r--firmware/test/i2s/i2stest.c25
-rw-r--r--firmware/test/test.c59
-rw-r--r--firmware/test/test.h33
6 files changed, 215 insertions, 42 deletions
diff --git a/firmware/drivers/i2s.c b/firmware/drivers/i2s.c
index df32801..2d900be 100644
--- a/firmware/drivers/i2s.c
+++ b/firmware/drivers/i2s.c
@@ -32,7 +32,7 @@ void i2s_set_power(int power)
// Remark: On reset, the I²S interface is disabled (PCI2S = 0).
uint32_t *pconp = (uint32_t *)0x400FC0C4;
*pconp &= ~(0b1 << 27); // Clear bit
- *pconp |= ~( ((power != 0) & 0b1) << 27); // Set bit
+ *pconp |= ((power != 0) & 0b1) << 27; // Set bit
}
void i2s_set_clksel(i2s_clksel_t sel)
@@ -91,7 +91,7 @@ void i2s_set_pinsel()
;
}
-void i2s_set_dao_register(wordwidth_t ww, channels_t ch)
+void i2s_set_dao_register(i2s_wordwidth_t ww, i2s_channels_t ch)
{
// See table 405, pg. 476
uint32_t *i2sdao = (uint32_t*)0x400A8000;
@@ -106,7 +106,7 @@ void i2s_set_dao_register(wordwidth_t ww, channels_t ch)
;
}
-void i2s_set_dai_register(wordwidth_t ww, channels_t ch)
+void i2s_set_dai_register(i2s_wordwidth_t ww, i2s_channels_t ch)
{
// See table 406, pg. 477
uint32_t *i2sdai = (uint32_t*)0x400A8004;
@@ -149,7 +149,7 @@ void i2s_set_rx_clock_bitrate(uint8_t bitrate)
*i2srxbitrate = (bitrate & 0b111111);
}
-void i2s_set_tx_mode_control(clksel_t c, int _4pin, int mcena)
+void i2s_set_tx_mode_control(i2s_tx_clksel_t c, int _4pin, int mcena)
{
// See table 417, pg 482
uint32_t *i2stxmode = (uint32_t*)0x400A8030;
@@ -159,7 +159,7 @@ void i2s_set_tx_mode_control(clksel_t c, int _4pin, int mcena)
;
}
-void i2s_set_rx_mode_control(clksel_t c, int _4pin, int mcena)
+void i2s_set_rx_mode_control(i2s_rx_clksel_t c, int _4pin, int mcena)
{
// See table 418, pg 483
uint32_t *i2srxmode = (uint32_t*)0x400A8034;
@@ -280,19 +280,54 @@ int i2s_get_state_tx_level()
return (*i2sstate >> 16) & 0b1111; // bit 16-19
}
-void i2s_init()
+int i2s_init(int pclkdiv, int bitrate, int x, int y,
+ int bitwidth, int channels)
{
i2s_set_power(1);
- i2s_set_clksel(I2S_CCLK_2);
+
+ i2s_clksel_t clk = I2S_CCLK;
+ switch(pclkdiv) {
+ case 1: clk = I2S_CCLK; break;
+ case 2: clk = I2S_CCLK_2; break;
+ case 4: clk = I2S_CCLK_4; break;
+ case 8: clk = I2S_CCLK_8; break;
+ default:
+ return 1;
+ }
+ i2s_set_clksel(clk);
+
i2s_set_pinsel();
- i2s_set_dao_register(WW_16_BIT, CH_STEREO);
- i2s_set_tx_rate(1, 1);
- i2s_set_tx_clock_bitrate(7);
+
+ i2s_wordwidth_t ww = I2S_WW_16_BIT;
+ switch(bitwidth) {
+ case 8: ww = I2S_WW_8_BIT; break;
+ case 16: ww = I2S_WW_16_BIT; break;
+ case 32: ww = I2S_WW_32_BIT; break;
+ default:
+ return 1;
+ }
+
+ i2s_channels_t ch = I2S_CH_MONO;
+ switch(channels) {
+ case 1: ch = I2S_CH_MONO; break;
+ case 2: ch = I2S_CH_STEREO; break;
+ default:
+ return 1;
+ }
+
+ i2s_set_dao_register(ww, ch);
+
+ if((x & 0xff) != x || (y & 0xff) != y) return 1;
+ i2s_set_tx_rate(x, y);
+
+ if((bitrate & 0b111111) != bitrate) return 1;
+ i2s_set_tx_clock_bitrate(bitrate);
+
i2s_set_tx_mode_control(CLK_TX_SRC, 1, 1);
- i2s_tx_reset();
+ //i2s_tx_reset();
i2s_tx_stop();
-
+ /*
int i;
i = i2s_get_state_irq();
i = i2s_get_state_dmareq1();
@@ -300,6 +335,8 @@ void i2s_init()
i = i2s_get_state_rx_level();
i = i2s_get_state_tx_level();
(void)i;
+ */
+ return 0;
}
#if 0
diff --git a/firmware/drivers/i2s.h b/firmware/drivers/i2s.h
index 8107e30..6a8d446 100644
--- a/firmware/drivers/i2s.h
+++ b/firmware/drivers/i2s.h
@@ -70,30 +70,30 @@ void i2s_set_clksel(i2s_clksel_t sel);
void i2s_set_pinsel();
typedef enum {
- WW_8_BIT = 0b00, // 8-bit data
- WW_16_BIT = 0b01, // 16-bit data
- // WW_RESERVED = 0b10, // Reserved, do not use this setting
- WW_32_BIT = 0b11, // 32-bit data
-} wordwidth_t;
+ I2S_WW_8_BIT = 0b00, // 8-bit data
+ I2S_WW_16_BIT = 0b01, // 16-bit data
+ //I2S_WW_RESERVED = 0b10, // Reserved, do not use this setting
+ I2S_WW_32_BIT = 0b11, // 32-bit data
+} i2s_wordwidth_t;
typedef enum {
- CH_MONO = 0b1, // Data is mono format
- CH_STEREO = 0b0, // Data is stereo format
-} channels_t;
+ I2S_CH_MONO = 0b1, // Data is mono format
+ I2S_CH_STEREO = 0b0, // Data is stereo format
+} i2s_channels_t;
/**
* Sets DAO register values and stops/resets the bus.
* @param ww Word width of pcm values.
* @param ch Number of channels (mono/stereo)
*/
-void i2s_set_dao_register(wordwidth_t ww, channels_t ch);
+void i2s_set_dao_register(i2s_wordwidth_t ww, i2s_channels_t ch);
/**
* Sets DAI register values and stops/resets the bus.
* @param ww Word width of pcm values.
* @param ch Number of channels (mono/stereo)
*/
-void i2s_set_dai_register(wordwidth_t ww, channels_t ch);
+void i2s_set_dai_register(i2s_wordwidth_t ww, i2s_channels_t ch);
/**
* Set clock transmit rate as PCLK_I2S * (X/Y) / 2
@@ -136,17 +136,22 @@ void i2s_set_rx_clock_bitrate(uint8_t bitrate);
typedef enum {
CLK_TX_SRC = 0b00, ///< Select the TX fractional rate divider clock output as the source
CLK_RX_MCLK = 0b10, ///< Select the RX_MCLK signal as the TX_MCLK clock source
-} clksel_t;
+} i2s_tx_clksel_t;
/**
*
*/
-void i2s_set_tx_mode_control(clksel_t c, int _4pin, int mcena);
+void i2s_set_tx_mode_control(i2s_tx_clksel_t c, int _4pin, int mcena);
+
+typedef enum {
+ CLK_RX_SRC = 0b00, ///< Select the RX fractional rate divider clock output as the source
+ CLK_TX_MCLK = 0b10, ///< Select the TX_MCLK signal as the RX_MCLK clock source
+} i2s_rx_clksel_t;
/**
*
*/
-void i2s_set_rx_mode_control(clksel_t c, int _4pin, int mcena);
+void i2s_set_rx_mode_control(i2s_rx_clksel_t c, int _4pin, int mcena);
void i2s_tx_reset();
void i2s_tx_stop();
@@ -173,14 +178,17 @@ void i2s_rx_start();
* I2STXFIFO: 0x400A 8008 - 8 x 32 bit (see table 407, pg 477)
*/
#define TF(t, n) t *n = (t*)0x400A8008
-inline void i2s_write_pcm_8_mono(int8_t s) { TF(int8_t, t); t[0] = s; }
-inline void i2s_write_pcm_16_mono(int16_t s) { TF(int16_t, t); t[0] = s; }
-inline void i2s_write_pcm_32_mono(int32_t s) { TF(int32_t, t); t[0] = s; }
-inline void i2s_write_pcm_8_stereo(int8_t l, int8_t r)
+static inline void i2s_write_pcm_8_mono(int8_t s)
+{ TF(int8_t, t); t[0] = s; }
+static inline void i2s_write_pcm_16_mono(int16_t s)
+{ TF(int16_t, t); t[0] = s; }
+static inline void i2s_write_pcm_32_mono(int32_t s)
+{ TF(int32_t, t); t[0] = s; }
+static inline void i2s_write_pcm_8_stereo(int8_t l, int8_t r)
{ TF(int8_t, t); t[0] = l; t[1] = r; }
-inline void i2s_write_pcm_16_stereo(int16_t l, int16_t r)
+static inline void i2s_write_pcm_16_stereo(int16_t l, int16_t r)
{ TF(int16_t, t); t[0] = l; t[1] = r; }
-inline void i2s_write_pcm_32_stereo(int32_t l, int32_t r)
+static inline void i2s_write_pcm_32_stereo(int32_t l, int32_t r)
{ TF(int32_t, t); t[0] = l; t[1] = r; }
/**
@@ -188,20 +196,31 @@ inline void i2s_write_pcm_32_stereo(int32_t l, int32_t r)
* I2SRXFIFO: 0x400A 800C - 8 x 32 bit (see table 408, pg 478)
*/
#define RF(t, n) t *n = (t*)0x400A800C
-inline void i2s_read_pcm_8_mono(int8_t *s) { RF(int8_t, t); *s = t[0]; }
-inline void i2s_read_pcm_16_mono(int16_t *s) { RF(int16_t, t); *s = t[0]; }
-inline void i2s_read_pcm_32_mono(int32_t *s) { RF(int32_t, t); *s = t[0]; }
-inline void i2s_read_pcm_8_stereo(int8_t *l, int8_t *r)
+static inline void i2s_read_pcm_8_mono(int8_t *s)
+{ RF(int8_t, t); *s = t[0]; }
+static inline void i2s_read_pcm_16_mono(int16_t *s)
+{ RF(int16_t, t); *s = t[0]; }
+static inline void i2s_read_pcm_32_mono(int32_t *s)
+{ RF(int32_t, t); *s = t[0]; }
+static inline void i2s_read_pcm_8_stereo(int8_t *l, int8_t *r)
{ RF(int8_t, t); *l = t[0]; *r = t[1]; }
-inline void i2s_read_pcm_16_stereo(int16_t *l, int16_t *r)
+static inline void i2s_read_pcm_16_stereo(int16_t *l, int16_t *r)
{ RF(int16_t, t); *l = t[0]; *r = t[1]; }
-inline void i2s_read_pcm_32_stereo(int32_t *l, int32_t *r)
+static inline void i2s_read_pcm_32_stereo(int32_t *l, int32_t *r)
{ RF(int32_t, t); *l = t[0]; *r = t[1]; }
/**
* Convenience function for power, pin, clock and register configuration.
+ * @param pclkdiv Value of pclkdiv as found by the clkcalc tool.
+ * @param bitrate Value of bitrate as found by the clkcalc tool.
+ * @param x Value of x as found by the clkcalc tool.
+ * @param y Value of y as found by the clkcalc tool.
+ * @param bitwidth Width of each sample in bits (8, 16 or 32).
+ * @param channels Number of channels (1 or 2).
+ * @return 0 on success, 1 on error.
*/
-void i2s_init();
+int i2s_init(int pclkdiv, int bitrate, int x, int y,
+ int bitwidth, int channels);
/**
diff --git a/firmware/test/i2s/Makefile b/firmware/test/i2s/Makefile
index c88f443..ed7860c 100644
--- a/firmware/test/i2s/Makefile
+++ b/firmware/test/i2s/Makefile
@@ -42,7 +42,9 @@ LINKER_SCRIPT = ${LPC}/LPC17xx.ld
CSRCS = \
${LPC}/system_LPC17xx.c \
${LPC}/startup_LPC17xx.c \
- ${DRV}/i2s.c
+ ${DRV}/led.c \
+ ${DRV}/i2s.c \
+ ../test.c
CSRCS += ${PROJ}.c
ASRCS =
@@ -91,8 +93,8 @@ nuke: clean
# openocd -f openocd.cfg -c 'flash write_image erase $(PROJ).hex' -c 'verify_image $(PROJ).hex' -c 'reset run'
flash: $(EXECNAME)
$(CP) -O binary $(EXECNAME) $(PROJ).bin
- ./fix-lpcchecksum $(PROJ).bin
- openocd -f openocd.cfg \
+ ../../fix-lpcchecksum $(PROJ).bin
+ openocd -f ../../openocd.cfg \
-c 'flash write_image erase $(PROJ).bin' \
-c 'verify_image $(PROJ).bin' \
-c 'reset run'
diff --git a/firmware/test/i2s/i2stest.c b/firmware/test/i2s/i2stest.c
index 16ea291..31f5c20 100644
--- a/firmware/test/i2s/i2stest.c
+++ b/firmware/test/i2s/i2stest.c
@@ -25,13 +25,36 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
#include <i2s.h>
+#include <led.h>
+
+#include "../test.h"
int main (void)
{
- i2s_init();
+ led_init();
+
+ // From: tools/clkcalc 48000 16 2
+ int pclkdiv = 1;
+ int bitrate = 24;
+ int x = 96;
+ int y = 125;
+
+ int bitwidth = 16;
+ int channels = 2;
+
+ int res = i2s_init(pclkdiv, bitrate, x, y, bitwidth, channels);
+
+ if(res) error();
i2s_tx_start();
+ // success();
+
+ int16_t s = 0;
while(1) {
+ //while(i2s_get_state_tx_level() < 3) {}
+ i2s_write_pcm_16_stereo(s, s);
+ if((s % 2) == 0) led_toggle();
+ s++;
}
}
diff --git a/firmware/test/test.c b/firmware/test/test.c
new file mode 100644
index 0000000..8671c5e
--- /dev/null
+++ b/firmware/test/test.c
@@ -0,0 +1,59 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/***************************************************************************
+ * test.c
+ *
+ * Sat Sep 13 21:10:33 CEST 2014
+ * Copyright 2014 Bent Bisballe Nyeng
+ * deva@aasimon.org
+ ****************************************************************************/
+
+/*
+ * This file is part of Pedal2Metal.
+ *
+ * Pedal2Metal 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.
+ *
+ * Pedal2Metal 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 Pedal2Metal; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+#include "test.h"
+
+#include <led.h>
+
+volatile int temp;
+
+static void delay(int del)
+{
+ int i;
+ for(i = 0; i < del; i++) {
+ temp = i;
+ }
+}
+
+// 21: slow, success
+// 17: fast, error
+static void blink(int t)
+{
+ while(1) {
+ led_toggle();
+ delay(1 << t);
+ }
+}
+
+void error()
+{
+ blink(17);
+}
+
+void success()
+{
+ blink(22);
+}
diff --git a/firmware/test/test.h b/firmware/test/test.h
new file mode 100644
index 0000000..9ab8484
--- /dev/null
+++ b/firmware/test/test.h
@@ -0,0 +1,33 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/***************************************************************************
+ * test.h
+ *
+ * Sat Sep 13 21:10:33 CEST 2014
+ * Copyright 2014 Bent Bisballe Nyeng
+ * deva@aasimon.org
+ ****************************************************************************/
+
+/*
+ * This file is part of Pedal2Metal.
+ *
+ * Pedal2Metal 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.
+ *
+ * Pedal2Metal 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 Pedal2Metal; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+#ifndef __PEDAL2METAL_TEST_H__
+#define __PEDAL2METAL_TEST_H__
+
+void error();
+void success();
+
+#endif/*__PEDAL2METAL_TEST_H__*/