diff options
-rw-r--r-- | src/fsm/audio.c | 68 | ||||
-rw-r--r-- | src/fsm/fsm.c | 2 | ||||
-rw-r--r-- | src/fsm/i2c.c | 137 | ||||
-rw-r--r-- | src/fsm/i2c.h | 40 | ||||
-rw-r--r-- | src/fsm/main.c | 24 | ||||
-rw-r--r-- | src/fsm/pio.c | 16 |
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; |