2015年2月8日日曜日

STM32F4 discoveryでSPI2通信

STM32F4 discoveryでSPI通信を試してみた。使ったのはSPI2。
通信相手は、microchip社のMCP23S17(IOエクスパンダ)。試したのはマイコンからの送信のみ。受信は後日。

SPI2を使うための手順は、以下。
  1. GPIOのクロックを有効化
  2. GPIOの初期化
  3. SPI2のクロックを有効化
  4. SPI2の初期化
  5. SPI2が割当てられている端子をGPIO→AF使用に設定
  6. SPI2を有効化
手順5のことをすっかり忘れていて、SPI2が動かなくて悩んでいたのは内緒。
main.cのほかに、mcp23s17.cとmcp23s17.hを作ってリンクする。

ソースコードは以下。




main.c

メインモジュール
#include "stm32f4xx.h"
#include "mcp23s17.h"


/*
  time : 約1uSec,1000000=1sec
*/
void delay(uint32_t time){
  uint32_t t;
  volatile uint8_t i;
  
  for(i=0;i<24;i++){
    t = time;
    while(t--);
  }
} 

//
void spi2_init(void){
  // structure to initialize GPIO
  GPIO_InitTypeDef GPIO_InitStructure;
  
  // GPIOB , SPI2 のクロックを有効化
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB,ENABLE);
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2,ENABLE);
  
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;  // PB13(SCK),PB14(MISO),PB15(MOSI)
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  GPIO_Init(GPIOB,&GPIO_InitStructure);

 //GPIOBのPIN13-15をオルタネィテブファンクションのSPI2に割り当て
  GPIO_PinAFConfig(GPIOB , GPIO_PinSource13 , GPIO_AF_SPI2);
  GPIO_PinAFConfig(GPIOB , GPIO_PinSource14 , GPIO_AF_SPI2);
  GPIO_PinAFConfig(GPIOB , GPIO_PinSource15 , GPIO_AF_SPI2);

  // PB12 はSPI2のCSとして使用
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;        // PB12(NSS)
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  GPIO_Init(GPIOB,&GPIO_InitStructure);

  // SPI2 設定
  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_1Edge;
  SPI_InitStructure.SPI_NSS       = SPI_NSS_Soft;
  SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;
  SPI_InitStructure.SPI_FirstBit  = SPI_FirstBit_MSB;

  SPI_Init(SPI2 , &SPI_InitStructure);
  SPI_Cmd(SPI2,ENABLE);
}


int main(void)
{
  /* structure to initialize GPIO */
  GPIO_InitTypeDef GPIO_InitStructure;

  SystemInit();

  // --------------------------------------------------
  // Port A 設定(SW入力) ここから
  //   SW on = 1 , off = 0
  // supply the clock to AHB1(GPIOD)
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);
  //GPIO pin configuration
  GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_0;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
  GPIO_Init(GPIOA,&GPIO_InitStructure);
  // Port A 設定(SW入力) ここから
  // --------------------------------------------------

  // --------------------------------------------------
  // Port D 設定(LED出力) ここから
  // PD12(LED4) , PD13(LED3) , PD14(LED5) , PD15(LED6)
  //  GPIOD->BSRRL(点灯) , GPIOD->BSRRH(消灯)
  // supply the clock to AHB1(GPIOD)
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD,ENABLE);
  //GPIO pin configuration
  GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
  GPIO_Init(GPIOD,&GPIO_InitStructure);
  // Port D 設定(LED出力) ここまで
  // --------------------------------------------------

  spi2_init();

  while(1){
    if(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0)){
      //ボタンが押されて1になっていたら以下を実行
      GPIO_SetBits(GPIOD,GPIO_Pin_13);       // 点灯
   while(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0));  // ボタンを放したら以下を実行
   
      mcp23s17_init(SPI2);
   mcp23s17_wr(SPI2,MCP23S17_IODIRA,0x00);
   mcp23s17_wr(SPI2,MCP23S17_GPIOA,0x01);    delay(1000000);
   mcp23s17_wr(SPI2,MCP23S17_GPIOA,0x02);    delay(1000000);
   mcp23s17_wr(SPI2,MCP23S17_GPIOA,0x04);    delay(1000000);
   mcp23s17_wr(SPI2,MCP23S17_GPIOA,0x08);    delay(1000000);
   mcp23s17_wr(SPI2,MCP23S17_GPIOA,0x04);    delay(1000000);
   mcp23s17_wr(SPI2,MCP23S17_GPIOA,0x02);    delay(1000000);
   mcp23s17_wr(SPI2,MCP23S17_GPIOA,0x01);    delay(1000000);
    }else{
      GPIO_ResetBits(GPIOD,GPIO_Pin_13);     // 消灯
    }
  }
  return 0;
}

mcp23s17.c

MCP23S17にアクセスするためのモジュールとか。
#include "stm32f4xx.h"
#include "mcp23s17.h"

/*
  MCP23S17 初期化
    BANK    = 0
 MIRROR  = 0
 SEQOP   = 1 (disable)
 DISSLW  = 0
 HAEN    = 0
 ODR     = 0
 INTPOL  = 0
*/
void mcp23s17_init(SPI_TypeDef *SPIx){
  MCP23S17_CS_ON();
    while (SPI_I2S_GetFlagStatus(SPIx, SPI_I2S_FLAG_TXE) == RESET);   // 送信バッファが空
    SPI_I2S_SendData(SPIx,MCP23S17_WR);
    while (SPI_I2S_GetFlagStatus(SPIx, SPI_I2S_FLAG_TXE) == RESET);   // 送信バッファが空
    SPI_I2S_SendData(SPIx,MCP23S17_IOCONA);
    while (SPI_I2S_GetFlagStatus(SPIx, SPI_I2S_FLAG_TXE) == RESET);   // 送信バッファが空
    SPI_I2S_SendData(SPIx,0x20);
    while (SPI_I2S_GetFlagStatus(SPIx, SPI_I2S_FLAG_BSY) == SET);     // 送信完了待ち
  MCP23S17_CS_OFF();
  MCP23S17_CS_ON();
    while (SPI_I2S_GetFlagStatus(SPIx, SPI_I2S_FLAG_TXE) == RESET);   // 送信バッファが空
    SPI_I2S_SendData(SPIx,MCP23S17_WR);
    while (SPI_I2S_GetFlagStatus(SPIx, SPI_I2S_FLAG_TXE) == RESET);   // 送信バッファが空
    SPI_I2S_SendData(SPIx,MCP23S17_IOCONB);
    while (SPI_I2S_GetFlagStatus(SPIx, SPI_I2S_FLAG_TXE) == RESET);   // 送信バッファが空
    SPI_I2S_SendData(SPIx,0x20);
    while (SPI_I2S_GetFlagStatus(SPIx, SPI_I2S_FLAG_BSY) == SET);     // 送信完了待ち
  MCP23S17_CS_OFF();
}

/*
  MCP23S17 ライト
*/
void mcp23s17_wr(SPI_TypeDef *SPIx , uint8_t reg , uint8_t data){
  MCP23S17_CS_ON();
    while (SPI_I2S_GetFlagStatus(SPIx, SPI_I2S_FLAG_TXE) == RESET);   // 送信バッファが空
    SPI_I2S_SendData(SPIx,MCP23S17_WR);
    while (SPI_I2S_GetFlagStatus(SPIx, SPI_I2S_FLAG_TXE) == RESET);   // 送信バッファが空
    SPI_I2S_SendData(SPIx,reg);
    while (SPI_I2S_GetFlagStatus(SPIx, SPI_I2S_FLAG_TXE) == RESET);   // 送信バッファが空
    SPI_I2S_SendData(SPIx,data);
    while (SPI_I2S_GetFlagStatus(SPIx, SPI_I2S_FLAG_BSY) == SET);     // 送信完了待ち
  MCP23S17_CS_OFF();
}

mcp23s17.h

MCP23S17にアクセスするための定義とか。


#ifndef _H_MCP23S17_
#define _H_MCP23S17_

/* MCP23S17 register map */
#define MCP23S17_IODIRA    0x00
#define MCP23S17_IODIRB    0x01
#define MCP23S17_IPOLA     0x02
#define MCP23S17_IPOLB     0x03
#define MCP23S17_GPINTENA  0x04
#define MCP23S17_GPINTENB  0x05
#define MCP23S17_DEFVALA   0x06
#define MCP23S17_DEFVALB   0x07
#define MCP23S17_INTCONA   0x08
#define MCP23S17_INTCONB   0x09
#define MCP23S17_IOCONA    0x0A
#define MCP23S17_IOCONB    0x0B
#define MCP23S17_GPPUA     0x0C
#define MCP23S17_GPPUB     0x0D
#define MCP23S17_INTFA     0x0E
#define MCP23S17_INTFB     0x0F
#define MCP23S17_INTCAPA   0x10
#define MCP23S17_INTCAPB   0x11
#define MCP23S17_GPIOA     0x12
#define MCP23S17_GPIOB     0x13
#define MCP23S17_OLATA     0x14
#define MCP23S17_OLATB     0x15


#define MCP23S17_CS_ON()  GPIO_ResetBits(GPIOB,GPIO_Pin_12)
#define MCP23S17_CS_OFF()  GPIO_SetBits(GPIOB,GPIO_Pin_12)

#define MCP23S17_WR 0x40
#define MCP23S17_RD 0x41

void mcp23s17_init(SPI_TypeDef *SPIx);
void mcp23s17_wr(SPI_TypeDef *SPIx , uint8_t reg , uint8_t data);

#endif


0 件のコメント:

コメントを投稿