aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/fsm/audio.c68
-rw-r--r--src/fsm/fsm.c2
-rw-r--r--src/fsm/i2c.c137
-rw-r--r--src/fsm/i2c.h40
-rw-r--r--src/fsm/main.c24
-rw-r--r--src/fsm/pio.c16
6 files changed, 225 insertions, 62 deletions
diff --git a/src/fsm/audio.c b/src/fsm/audio.c
index 752ad12..02123fd 100644
--- a/src/fsm/audio.c
+++ b/src/fsm/audio.c
@@ -1,4 +1,5 @@
#include "audio.h"
+#include "i2c.h"
#include "stm32f4xx_conf.h"
#include "stm32f4xx.h"
@@ -32,10 +33,10 @@ void InitializeAudio(int plln, int pllr, int i2sdiv, int i2sodd) {
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE);
-
- RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI3, ENABLE);
+ i2c_init();
+
// Configure reset pin.
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
@@ -44,17 +45,6 @@ void InitializeAudio(int plln, int pllr, int i2sdiv, int i2sodd) {
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOD, &GPIO_InitStructure);
- // Configure I2C SCL and SDA pins.
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_9;
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
- GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;
- GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
- GPIO_Init(GPIOB, &GPIO_InitStructure);
-
- GPIO_PinAFConfig(GPIOB, GPIO_PinSource6, GPIO_AF_I2C1);
- GPIO_PinAFConfig(GPIOB, GPIO_PinSource9, GPIO_AF_I2C1);
-
// Configure I2S MCK, SCK, SD pins.
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7 | GPIO_Pin_10 | GPIO_Pin_12;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
@@ -84,27 +74,6 @@ void InitializeAudio(int plln, int pllr, int i2sdiv, int i2sodd) {
}
GPIOD ->BSRRL = 1 << 4;
- // Reset I2C.
- RCC_APB1PeriphResetCmd(RCC_APB1Periph_I2C1, ENABLE);
- RCC_APB1PeriphResetCmd(RCC_APB1Periph_I2C1, DISABLE);
-
- // Configure I2C.
- uint32_t pclk1 = 42000000;
-
- I2C1 ->CR2 = pclk1 / 1000000; // Configure frequency and disable interrupts and DMA.
- I2C1 ->OAR1 = I2C_OAR1_ADDMODE | 0x33;
-
- // Configure I2C speed in standard mode.
- const uint32_t i2c_speed = 100000;
- int ccrspeed = pclk1 / (i2c_speed * 2);
- if (ccrspeed < 4) {
- ccrspeed = 4;
- }
- I2C1 ->CCR = ccrspeed;
- I2C1 ->TRISE = pclk1 / 1000000 + 1;
-
- I2C1 ->CR1 = I2C_CR1_ACK | I2C_CR1_PE; // Enable and configure the I2C peripheral.
-
// Configure codec.
WriteRegister(0x02, 0x01); // Keep codec powered off.
WriteRegister(0x04, 0xaf); // SPK always off and HP always on.
@@ -217,30 +186,6 @@ bool ProvideAudioBufferWithoutBlocking(void *samples, int numsamples) {
return true;
}
-static void WriteRegister(uint8_t address, uint8_t value) {
- while (I2C1 ->SR2 & I2C_SR2_BUSY )
- ;
-
- I2C1 ->CR1 |= I2C_CR1_START; // Start the transfer sequence.
- while (!(I2C1 ->SR1 & I2C_SR1_SB ))
- ; // Wait for start bit.
-
- I2C1 ->DR = 0x94;
- while (!(I2C1 ->SR1 & I2C_SR1_ADDR ))
- ; // Wait for master transmitter mode.
- I2C1 ->SR2;
-
- I2C1 ->DR = address; // Transmit the address to write to.
- while (!(I2C1 ->SR1 & I2C_SR1_TXE ))
- ; // Wait for byte to move to shift register.
-
- I2C1 ->DR = value; // Transmit the value.
-
- while (!(I2C1 ->SR1 & I2C_SR1_BTF ))
- ; // Wait for all bytes to finish.
- I2C1 ->CR1 |= I2C_CR1_STOP; // End the transfer sequence.
-}
-
static void StartAudioDMAAndRequestBuffers() {
// Configure DMA stream.
DMA1_Stream7 ->CR = (0 * DMA_SxCR_CHSEL_0 ) | // Channel 0
@@ -283,3 +228,10 @@ void DMA1_Stream7_IRQHandler() {
DMARunning = false;
}
}
+
+static void WriteRegister(uint8_t address, uint8_t value)
+{
+ const uint8_t device = 0x4a;
+ const uint8_t data[2] = {address, value};
+ i2c_write(device, data, 2);
+}
diff --git a/src/fsm/fsm.c b/src/fsm/fsm.c
index d8a3a5c..8b7f105 100644
--- a/src/fsm/fsm.c
+++ b/src/fsm/fsm.c
@@ -340,6 +340,8 @@ void fsm_update() {
break;
}
+
+
if (next_state != current_state) {
timestamp_state[next_state] = timestamp_now();
}
diff --git a/src/fsm/i2c.c b/src/fsm/i2c.c
new file mode 100644
index 0000000..da109fc
--- /dev/null
+++ b/src/fsm/i2c.c
@@ -0,0 +1,137 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2015 Matthias P. Braendli
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+*/
+
+#include "i2c.h"
+#include "stm32f4xx_conf.h"
+#include "stm32f4xx_i2c.h"
+#include "stm32f4xx.h"
+
+static int i2c_init_done = 0;
+
+static I2C_TypeDef* const I2Cx = I2C1;
+
+void i2c_init()
+{
+ if (i2c_init_done == 1) {
+ return;
+ }
+
+ RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);
+ RCC_APB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
+
+ // Configure I2C SCL and SDA pins.
+ GPIO_InitTypeDef GPIO_InitStructure;
+ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_9;
+ GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
+ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
+ GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;
+ GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
+ GPIO_Init(GPIOB, &GPIO_InitStructure);
+
+ GPIO_PinAFConfig(GPIOB, GPIO_PinSource6, GPIO_AF_I2C1);
+ GPIO_PinAFConfig(GPIOB, GPIO_PinSource9, GPIO_AF_I2C1);
+
+ // Reset I2C.
+ RCC_APB1PeriphResetCmd(RCC_APB1Periph_I2C1, ENABLE);
+ RCC_APB1PeriphResetCmd(RCC_APB1Periph_I2C1, DISABLE);
+
+ // configure I2C1
+ I2C_InitTypeDef I2C_InitStruct;
+ I2C_InitStruct.I2C_ClockSpeed = 100000; //Hz
+ I2C_InitStruct.I2C_Mode = I2C_Mode_I2C;
+ I2C_InitStruct.I2C_DutyCycle = I2C_DutyCycle_2; // 50% duty cycle
+ I2C_InitStruct.I2C_OwnAddress1 = 0x00; // not relevant in master mode
+
+ // disable acknowledge when reading (can be changed later on)
+ I2C_InitStruct.I2C_Ack = I2C_Ack_Disable;
+
+ I2C_InitStruct.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
+ I2C_Init(I2C1, &I2C_InitStruct);
+
+ // enable I2C1
+ I2C_Cmd(I2C1, ENABLE);
+
+ i2c_init_done = 1;
+}
+
+
+static void i2c_start(uint8_t device, uint8_t direction)
+{
+ while(I2C_GetFlagStatus(I2Cx, I2C_FLAG_BUSY));
+ I2C_GenerateSTART(I2Cx, ENABLE);
+ // wait for I2C1 EV5 --> Slave has acknowledged start condition
+ while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_MODE_SELECT));
+
+ // Send slave Address for write
+ I2C_Send7bitAddress(I2Cx, device << 1, direction);
+
+ /* wait for I2C1 EV6, check if
+ * either Slave has acknowledged Master transmitter or
+ * Master receiver mode, depending on the transmission
+ * direction
+ */
+ if(direction == I2C_Direction_Transmitter) {
+ while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
+ }
+ else if(direction == I2C_Direction_Receiver) {
+ while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));
+ }
+}
+
+static void i2c_send(uint8_t data) {
+ I2C_SendData(I2Cx, data);
+ // wait for I2C1 EV8_2 --> byte has been transmitted
+ while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
+}
+
+void i2c_write(uint8_t device, const uint8_t *txbuf, int len) {
+ i2c_start(device, I2C_Direction_Transmitter);
+ for (int i = 0; i < len; i++) {
+ i2c_send(txbuf[i]);
+ }
+ I2C_GenerateSTOP(I2Cx, ENABLE);
+}
+
+int i2c_read(uint8_t device, uint8_t *rxbuf, int len)
+{
+ i2c_start(device, I2C_Direction_Receiver);
+ for (int i = 0; i < len; i++) {
+ if (i < len-1) {
+ I2C_AcknowledgeConfig(I2Cx, ENABLE);
+ // wait until one byte has been received
+ while( !I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_RECEIVED) );
+ rxbuf[i] = I2C_ReceiveData(I2Cx);
+ }
+ else {
+ I2C_AcknowledgeConfig(I2Cx, DISABLE);
+ I2C_GenerateSTOP(I2Cx, ENABLE);
+ // wait until one byte has been received
+ while( !I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_RECEIVED) );
+ rxbuf[i] = I2C_ReceiveData(I2Cx);
+ }
+ }
+
+ return len;
+}
+
diff --git a/src/fsm/i2c.h b/src/fsm/i2c.h
new file mode 100644
index 0000000..2e2dbd3
--- /dev/null
+++ b/src/fsm/i2c.h
@@ -0,0 +1,40 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2015 Matthias P. Braendli
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+*/
+
+#ifndef __I2C_H_
+#define __I2C_H_
+
+#include <stdint.h>
+
+/* Initialise I2C on the board for both the audio codec and the GPS receiver */
+void i2c_init();
+
+/* Do an I2C write */
+void i2c_write(uint8_t device, const uint8_t *txbuf, int len);
+
+/* Do an I2C write into rxbuf. Returns number of bytes received */
+int i2c_read(uint8_t device, uint8_t *rxbuf, int len);
+
+#endif // __I2C_H_
+
diff --git a/src/fsm/main.c b/src/fsm/main.c
index 903f874..225b2f9 100644
--- a/src/fsm/main.c
+++ b/src/fsm/main.c
@@ -1,3 +1,27 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2015 Matthias P. Braendli
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+*/
+
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
diff --git a/src/fsm/pio.c b/src/fsm/pio.c
index 4a83e8d..a5f7b9d 100644
--- a/src/fsm/pio.c
+++ b/src/fsm/pio.c
@@ -54,7 +54,6 @@ void pio_init()
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_Init(GPIOC, &GPIO_InitStructure);
-
xTaskCreate(
read_fsm_input_task,
"TaskPIO",
@@ -66,15 +65,24 @@ void pio_init()
void pio_set_fsm_signals(struct fsm_input_signals_t* sig)
{
- *sig = pio_signals;
+ // We do not want to copy the data, we want to
+ // set the fields in sig only to 1, never to
+ // zero.
+ // The FSM sets the input fields back to 0.
+ uint8_t *in_signals = (uint8_t*)&pio_signals;
+ uint8_t *out_signals = (uint8_t*)sig;
+
+ for (int i = 0; i < sizeof(struct fsm_input_signals_t); i++) {
+ out_signals[i] |= in_signals[i];
+ }
}
void read_fsm_input_task(void *pvParameters)
{
while (1) {
- pio_signals.qrp = GPIO_ReadInputDataBit(GPIOC, GPIO_PIN_QRP_n) ? 0 : 1;
+ pio_signals.qrp = GPIO_ReadInputDataBit(GPIOC, GPIO_PIN_QRP_n) ? 0 : 1;
pio_signals.tone_1750 = GPIO_ReadInputDataBit(GPIOC, GPIO_PIN_1750) ? 1 : 0;
- pio_signals.carrier = GPIO_ReadInputDataBit(GPIOC, GPIO_PIN_RX_n) ? 0 : 1;
+ pio_signals.carrier = GPIO_ReadInputDataBit(GPIOC, GPIO_PIN_RX_n) ? 0 : 1;
pio_signals.discrim_u = GPIO_ReadInputDataBit(GPIOC, GPIO_PIN_U_n) ? 0 : 1;
pio_signals.discrim_d = GPIO_ReadInputDataBit(GPIOC, GPIO_PIN_D_n) ? 0 : 1;