adding preliminary support for sc18is600 spi to I2C converter

This commit is contained in:
Antoine Drouin
2010-07-21 17:58:50 +00:00
parent 107480578f
commit 62fc96e522
5 changed files with 475 additions and 0 deletions
@@ -0,0 +1,283 @@
#include "peripherals/booz_sc18is600.h"
#include <stm32/rcc.h>
#include <stm32/spi.h>
#include <stm32/exti.h>
#include <stm32/misc.h>
#include <stm32/dma.h>
#include <stm32/gpio.h>
/* commands definition */
#define Sc18Is600_Cmd_Write 0x00
#define Sc18Is600_Cmd_Read 0x01
#define Sc18Is600_Cmd_Read_After_Write 0x02
#define Sc18Is600_Cmd_Write_After_Write 0x03
#define Sc18Is600_Cmd_Read_Buffer 0x06
#define Sc18Is600_Cmd_Write_To_Reg 0x20
#define Sc18Is600_Cmd_Read_From_Reg 0x21
#define Sc18Is600_Cmd_Power_Down 0x30
extern void exti2_irq_handler(void);
extern void dma1_c4_irq_handler(void);
static inline void sc18is600_setup_SPI_DMA(uint8_t _len);
void sc18is600_arch_init(void) {
/* set slave select as output and assert it ( on PB12) */
Sc18Is600Unselect();
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
/* configure external interrupt exti2 on PD2( data ready ) */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD | RCC_APB2Periph_AFIO, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOD, &GPIO_InitStructure);
EXTI_InitTypeDef EXTI_InitStructure;
GPIO_EXTILineConfig(GPIO_PortSourceGPIOD, GPIO_PinSource2);
EXTI_InitStructure.EXTI_Line = EXTI_Line2;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = EXTI2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x0F;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x0F;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
/* Enable DMA1 channel4 IRQ Channel */
NVIC_InitTypeDef NVIC_init_struct = {
.NVIC_IRQChannel = DMA1_Channel4_IRQn,
.NVIC_IRQChannelPreemptionPriority = 0,
.NVIC_IRQChannelSubPriority = 0,
.NVIC_IRQChannelCmd = ENABLE
};
NVIC_Init(&NVIC_init_struct);
/* Enable SPI2 Periph clock -------------------------------------------------*/
RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);
/* Configure GPIOs: SCK, MISO and MOSI --------------------------------*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOB, &GPIO_InitStructure);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO , ENABLE);
/* configure SPI */
SPI_InitTypeDef SPI_InitStructure;
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;
SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_64;
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
SPI_InitStructure.SPI_CRCPolynomial = 7;
SPI_Init(SPI2, &SPI_InitStructure);
/* Enable SPI */
SPI_Cmd(SPI2, ENABLE);
/* Enable SPI_2 DMA clock ---------------------------------------------------*/
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
}
static inline void sc18is600_setup_SPI_DMA(uint8_t _len) {
/* SPI2_Rx_DMA_Channel configuration ------------------------------------*/
DMA_DeInit(DMA1_Channel4);
DMA_InitTypeDef DMA_initStructure_4 = {
.DMA_PeripheralBaseAddr = (uint32_t)(SPI2_BASE+0x0C),
.DMA_MemoryBaseAddr = (uint32_t)sc18is600.priv_rx_buf,
.DMA_DIR = DMA_DIR_PeripheralSRC,
.DMA_BufferSize = _len,
.DMA_PeripheralInc = DMA_PeripheralInc_Disable,
.DMA_MemoryInc = DMA_MemoryInc_Enable,
.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte,
.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte,
.DMA_Mode = DMA_Mode_Normal,
.DMA_Priority = DMA_Priority_VeryHigh,
.DMA_M2M = DMA_M2M_Disable
};
DMA_Init(DMA1_Channel4, &DMA_initStructure_4);
/* SPI2_Tx_DMA_Channel configuration ------------------------------------*/
DMA_DeInit(DMA1_Channel5);
DMA_InitTypeDef DMA_initStructure_5 = {
.DMA_PeripheralBaseAddr = (uint32_t)(SPI2_BASE+0x0C),
.DMA_MemoryBaseAddr = (uint32_t)sc18is600.priv_tx_buf,
.DMA_DIR = DMA_DIR_PeripheralDST,
.DMA_BufferSize = _len,
.DMA_PeripheralInc = DMA_PeripheralInc_Disable,
.DMA_MemoryInc = DMA_MemoryInc_Enable,
.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte,
.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte,
.DMA_Mode = DMA_Mode_Normal,
.DMA_Priority = DMA_Priority_Medium,
.DMA_M2M = DMA_M2M_Disable
};
DMA_Init(DMA1_Channel5, &DMA_initStructure_5);
/* Enable SPI_2 Rx request */
SPI_I2S_DMACmd(SPI2, SPI_I2S_DMAReq_Rx, ENABLE);
/* Enable DMA1 Channel4 */
DMA_Cmd(DMA1_Channel4, ENABLE);
/* Enable SPI_2 Tx request */
SPI_I2S_DMACmd(SPI2, SPI_I2S_DMAReq_Tx, ENABLE);
/* Enable DMA1 Channel5 */
DMA_Cmd(DMA1_Channel5, ENABLE);
/* Enable DMA1 Channel4 Transfer Complete interrupt */
DMA_ITConfig(DMA1_Channel4, DMA_IT_TC, ENABLE);
}
void sc18is600_transmit(uint8_t addr, uint8_t len) {
sc18is600.transaction = Sc18Is600Transmit;
sc18is600.status = Sc18Is600SendingRequest;
sc18is600.priv_tx_buf[0] = Sc18Is600_Cmd_Write; // write command
sc18is600.priv_tx_buf[1] = len;
sc18is600.priv_tx_buf[2] = addr;
Sc18Is600Select();
sc18is600_setup_SPI_DMA(len+3);
}
void sc18is600_receive(uint8_t addr, uint8_t len) {
}
void sc18is600_tranceive(uint8_t addr, uint8_t len_tx, uint8_t len_rx) {
sc18is600.transaction = Sc18Is600Transcieve;
sc18is600.status = Sc18Is600SendingRequest;
sc18is600.rx_len = len_rx;
sc18is600.priv_tx_buf[0] = Sc18Is600_Cmd_Read_After_Write; // read after write command
sc18is600.priv_tx_buf[1] = len_tx;
sc18is600.priv_tx_buf[2] = len_rx;
sc18is600.priv_tx_buf[3] = addr;
sc18is600.priv_tx_buf[4+len_tx] = addr;
Sc18Is600Select();
sc18is600_setup_SPI_DMA(len_tx+5);
}
void sc18is600_write_to_register(uint8_t addr, uint8_t value) {
sc18is600.transaction = Sc18Is600WriteRegister;
sc18is600.status = Sc18Is600SendingRequest;
sc18is600.priv_tx_buf[0] = Sc18Is600_Cmd_Write_To_Reg; // write to register
sc18is600.priv_tx_buf[1] = addr;
sc18is600.priv_tx_buf[2] = value;
Sc18Is600Select();
sc18is600_setup_SPI_DMA(3);
}
void sc18is600_read_from_register(uint8_t addr) {
sc18is600.transaction = Sc18Is600ReadRegister;
sc18is600.status = Sc18Is600SendingRequest;
sc18is600.priv_tx_buf[0] = Sc18Is600_Cmd_Read_From_Reg; // read from register
sc18is600.priv_tx_buf[1] = addr;
sc18is600.priv_tx_buf[2] = 0;
Sc18Is600Select();
sc18is600_setup_SPI_DMA(3);
}
#define ReadI2CStatReg() { \
sc18is600.priv_tx_buf[0] = Sc18Is600_Cmd_Read_From_Reg; \
sc18is600.priv_tx_buf[1] = Sc18Is600_I2CStat; \
sc18is600.priv_tx_buf[2] = 0; \
Sc18Is600Select(); \
sc18is600_setup_SPI_DMA(3); \
}
void exti2_irq_handler(void) {
/* clear EXTI */
if(EXTI_GetITStatus(EXTI_Line2) != RESET)
EXTI_ClearITPendingBit(EXTI_Line2);
switch (sc18is600.transaction) {
case Sc18Is600Receive:
case Sc18Is600Transmit:
case Sc18Is600Transcieve:
if (sc18is600.status == Sc18Is600WaitingForI2C) {
sc18is600.status = Sc18Is600ReadingI2CStat;
ReadI2CStatReg();
}
break;
case Sc18Is600ReadRegister:
case Sc18Is600WriteRegister:
// should not happen
break;
default:
break;
}
}
void dma1_c4_irq_handler(void) {
DMA_ITConfig(DMA1_Channel4, DMA_IT_TC, DISABLE);
/* Disable SPI_2 Rx and TX request */
SPI_I2S_DMACmd(SPI2, SPI_I2S_DMAReq_Rx, DISABLE);
SPI_I2S_DMACmd(SPI2, SPI_I2S_DMAReq_Tx, DISABLE);
/* Disable DMA1 Channel4 and 5 */
DMA_Cmd(DMA1_Channel4, DISABLE);
DMA_Cmd(DMA1_Channel5, DISABLE);
switch (sc18is600.transaction) {
case Sc18Is600ReadRegister:
case Sc18Is600WriteRegister:
sc18is600.status = Sc18Is600TransactionComplete;
Sc18Is600Unselect();
break;
case Sc18Is600Transmit:
if (sc18is600.status==Sc18Is600SendingRequest) {
sc18is600.status = Sc18Is600WaitingForI2C;
Sc18Is600Unselect();
}
else if (sc18is600.status == Sc18Is600ReadingI2CStat) {
sc18is600.i2c_status = sc18is600.priv_rx_buf[2];
sc18is600.status = Sc18Is600TransactionComplete;
Sc18Is600Unselect();
}
break;
case Sc18Is600Receive:
case Sc18Is600Transcieve:
if (sc18is600.status==Sc18Is600SendingRequest) {
sc18is600.status = Sc18Is600WaitingForI2C;
Sc18Is600Unselect();
}
else if (sc18is600.status == Sc18Is600ReadingI2CStat) {
sc18is600.status = Sc18Is600ReadingBuffer;
sc18is600.priv_tx_buf[0] = Sc18Is600_Cmd_Read_Buffer;
// debug
for (int i=1; i<sc18is600.rx_len+1; i++) sc18is600.priv_tx_buf[i] = 0;
Sc18Is600Select();
sc18is600_setup_SPI_DMA(sc18is600.rx_len+1);
}
else if (sc18is600.status == Sc18Is600ReadingBuffer) {
sc18is600.status = Sc18Is600TransactionComplete;
Sc18Is600Unselect();
}
break;
default:
break;
}
}
@@ -0,0 +1,9 @@
#ifndef BOOZ_SC18IS600_ARCH_H
#define BOOZ_SC18IS600_ARCH_H
#define Sc18Is600Unselect() GPIOB->BSRR = GPIO_Pin_12
#define Sc18Is600Select() GPIOB->BRR = GPIO_Pin_12
#endif /* BOOZ_SC18IS600_ARCH_H */
@@ -0,0 +1,11 @@
#include "booz/peripherals/booz_sc18is600.h"
struct Sc18Is600 sc18is600;
void sc18is600_init(void) {
sc18is600.status = Sc18Is600Idle;
sc18is600_arch_init();
}
@@ -0,0 +1,55 @@
#ifndef SC18IS600_H
#define SC18IS600_H
#include "std.h"
/* Register definitions */
#define Sc18Is600_IOConfig 0x00
#define Sc18Is600_IOState 0x01
#define Sc18Is600_I2CClock 0x02
#define Sc18Is600_I2CTO 0x03
#define Sc18Is600_I2CStat 0x04
#define Sc18Is600_I2CAdr 0x05
enum Sc18Is600Status {
Sc18Is600Idle,
Sc18Is600SendingRequest,
Sc18Is600WaitingForI2C,
Sc18Is600ReadingI2CStat,
Sc18Is600ReadingBuffer,
Sc18Is600TransactionComplete,
};
enum Sc18Is600Transaction {
Sc18Is600Transmit,
Sc18Is600Receive,
Sc18Is600Transcieve,
Sc18Is600ReadRegister,
Sc18Is600WriteRegister,
};
#define SC18IS600_BUF_LEN 96
struct Sc18Is600 {
enum Sc18Is600Status status;
enum Sc18Is600Transaction transaction;
uint8_t priv_tx_buf[SC18IS600_BUF_LEN];
uint8_t priv_rx_buf[SC18IS600_BUF_LEN];
uint8_t rx_len;
uint8_t i2c_status;
};
extern struct Sc18Is600 sc18is600;
extern void sc18is600_init(void);
extern void sc18is600_transmit(uint8_t addr, uint8_t len);
extern void sc18is600_receive(uint8_t addr, uint8_t len);
extern void sc18is600_tranceive(uint8_t addr, uint8_t len_tx, uint8_t len_rx);
extern void sc18is600_write_to_register(uint8_t addr, uint8_t value);
extern void sc18is600_read_from_register(uint8_t addr);
#include "peripherals/booz_sc18is600_arch.h"
extern void sc18is600_arch_init(void);
#endif /* SC18IS600_H */
+117
View File
@@ -0,0 +1,117 @@
/*
* $Id$
*
* Copyright (C) 2009 Antoine Drouin <poinix@gmail.com>
*
* This file is part of paparazzi.
*
* paparazzi 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, or (at your option)
* any later version.
*
* paparazzi 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 paparazzi; see the file COPYING. If not, write to
* the Free Software Foundation, 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include <stm32/gpio.h>
#include <stm32/flash.h>
#include <stm32/misc.h>
#include BOARD_CONFIG
#include "init_hw.h"
#include "sys_time.h"
#include "downlink.h"
#include "booz/peripherals/booz_sc18is600.h"
static inline void main_init( void );
static inline void main_periodic_task( void );
static inline void main_event_task( void );
static inline void main_spi2_init(void);
int main(void) {
main_init();
while(1) {
if (sys_time_periodic())
main_periodic_task();
main_event_task();
}
return 0;
}
static inline void main_init( void ) {
hw_init();
sys_time_init();
sc18is600_init();
main_spi2_init();
}
static inline void main_periodic_task( void ) {
// LED_TOGGLE(6);
RunOnceEvery(10,
{
DOWNLINK_SEND_ALIVE(DefaultChannel, 16, MD5SUM);
LED_PERIODIC();
});
static uint8_t foo=0;
switch (foo) {
case 2:
/* set I2C clock to 400khz */
sc18is600_write_to_register(Sc18Is600_I2CClock, 0x05);
break;
case 3:
/* read it back, just to check */
sc18is600_read_from_register(Sc18Is600_I2CClock);
break;
case 4:
/* set gyro range to 2000deg/s : write 0x03 to register at addr 0x16 */
sc18is600.priv_tx_buf[3] = 0x16;
sc18is600.priv_tx_buf[4] = 0x03;
sc18is600_transmit(0xD0, 2);
break;
case 5:
/* reads 8 bytes from address 0x1b */
sc18is600.priv_tx_buf[4] = 0x1b;
sc18is600_tranceive(0xD0, 1, 8);
break;
}
if (foo< 5) foo++;
}
static inline void main_event_task( void ) {
}
static inline void main_spi2_init( void ) {
/* set mag ss as output and assert it (on PC12) ------------------------------*/
/* set mag reset as output and assert it (on PC13) ------------------------------*/
/* set eeprom ss as output and assert it (on PC14) ------------------------------*/
GPIOC->BSRR = GPIO_Pin_12;
GPIOC->BSRR = GPIO_Pin_13;
GPIOC->BSRR = GPIO_Pin_14;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12 | GPIO_Pin_13|GPIO_Pin_14;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOC, &GPIO_InitStructure);
}