SSブログ

STM32F103のUSARTを送受信割込みで使ってみる [ARM&Cortex-M3]

つまり低水準入出力関数の更に下の階層ですな。
※一部のtx、rxのリマップに修正を加えています。

使い方
void hoge( void )
{
  char SndBuf[ 128 ],RcvBuf[ 128 ];
  SCI_BUFFER snd,rcv;

  snd.buf = SndBuf;
  snd.wptr = snd.rptr = 0;
  snd.size = sizeof(SndBuf);
  rcv.buf = RcvBuf;
  rcv.wptr = rcv.rptr = 0;
  rcv.size = sizeof(RcvBuf);
  (void)SCI_Init( SCI_1, &rcv, &snd, BAUD_115200 );

  while( 1 )
  {
    while( RcvSizeOfBuf( SCI_1 ) == 0 ) ;
    SCI_Putc( SCI_1, SCI_Getc( SCI_1 ) );
  }
}


ヘッダーファイル
/*************************************************************************/
/* STM32F103VBT6のUSARTを使う                                            */
/* USART1はPA9,PA10、USART2はPD5,PD6、USART3はPD8,PD9に接続されている。  */
/*                                 designed by hamayan since 2008/11/06  */
/*************************************************************************/

/*************************************************************************/
/* ボーレート定義                                                        */
/*************************************************************************/
#define  BAUD_230400  (0x00000271UL / 2)
#define  BAUD_115200  (0x00000271UL)
#define  BAUD_57600   (0x000004E2UL)
#define  BAUD_38400   (0x00000753UL)
#define  BAUD_19200   (0x00000EA6UL)
#define  BAUD_9600    (0x00001D4CUL)

/*************************************************************************/
/* 端子定義                                                              */
/*************************************************************************/

/*************************************************************************/
/* IOレジスタ定義                                                        */
/*************************************************************************/

/*************************************************************************/
/* レジスタ bit定義                                                      */
/*************************************************************************/
/*SR*/
#define  PE_Bit     0x00000001
#define  FE_Bit     0x00000002
#define  NE_Bit     0x00000004
#define  ORE_Bit    0x00000008
#define  IDLE_Bit   0x00000010
#define  RXNE_Bit   0x00000020
#define  TC_Bit     0x00000040
#define  TXE_Bit    0x00000080
#define  LBD_Bit    0x00000100
#define  CTS_Bit    0x00000200

/*CR1*/
#define  SBK_Bit    0x00000001
#define  RWU_Bit    0x00000002
#define  RE_Bit     0x00000004
#define  TE_Bit     0x00000008
#define  IDLEIE_Bit 0x00000010
#define  RXNEIE_Bit 0x00000020
#define  TCIE_Bit   0x00000040
#define  TXEIE_Bit  0x00000080
#define  PEIE_Bit   0x00000100
#define  PS_Bit     0x00000200
#define  PCE_Bit    0x00000400
#define  WAKE_Bit   0x00000800
#define  M_Bit      0x00001000
#define  UE_Bit     0x00002000

/*CR2*/
#define  LBDL_Bit   0x00000020
#define  LBDIE_Bit  0x00000040
#define  LBCL_Bit   0x00000100
#define  CPHA_Bit   0x00000200
#define  CPOL_Bit   0x00000400
#define  CLKEN_Bit  0x00000800
#define  STOP0_Bit  0x00001000
#define  STOP1_Bit  0x00002000
#define  LINEN_Bit  0x00004000

/*CR3*/
#define  EIE_Bit    0x00000001
#define  IREN_Bit   0x00000002
#define  IRLP_Bit   0x00000004
#define  HDSEL_Bit  0x00000008
#define  NACK_Bit   0x00000010
#define  SCEN_Bit   0x00000020
#define  DMAR_Bit   0x00000040
#define  DMAT_Bit   0x00000080
#define  RTSE_Bit   0x00000100
#define  CTSE_Bit   0x00000200
#define  CTSIE_Bit  0x00000400

/*************************************************************************/
/* その他の定義                                                          */
/*************************************************************************/
typedef enum
{
  SCI_1 = 0, SCI_2, SCI_3, SCI_4, SCI_5,
} SciNum_t;

typedef struct
{
  unsigned long sr;
  unsigned long dr;
  unsigned long brr;
  unsigned long cr1;
  unsigned long cr2;
  unsigned long cr3;
  unsigned long gtpr;
} SCI_REG;

typedef struct
{
  void *buf; 
  unsigned short wptr,rptr; 
  unsigned short size;
} SCI_BUFFER;

/*************************************************************************/
/* 大域変数宣言                                                          */
/*************************************************************************/

/*************************************************************************/
/* プロトタイプ宣言                                                      */
/*************************************************************************/
int SCI_Init( int ch, SCI_BUFFER *rcv, SCI_BUFFER *snd, unsigned long brr );
int SCI_Putc( int ch, char c );
int SCI_Puts( int ch, char *str );
int SCI_Getc( int ch );
unsigned short RcvSizeOfBuf( int ch );
unsigned short SndSizeOfBuf( int ch );
void SCI_ISR( int ch );
unsigned long SCI_Status( int ch );
char SCI_DirectRead( int ch );

/*************************************************************************/
/* end of file                                                           */
/*                                 designed by hamayan since 2008/11/06  */
/*************************************************************************/


Cソース
/*************************************************************************/
/* STM32F103VBT6のUSARTを何とかする                                      */
/*                                 designed by hamayan since 2008/11/06  */
/*************************************************************************/
#include  "stm32f10x_lib.h"
//#include  "delivertive.h"
#include  "usart.h"
#define   PA_CRH     (GPIOA->CRH)
#define   PC_CRH     (GPIOC->CRH)
#define   PD_CRL     (GPIOD->CRL)
#define   PD_CRH     (GPIOD->CRH)
#define   AFIO_MAPR  (AFIO->MAPR)

/*************************************************************************/
/* 端子定義                                                              */
/*************************************************************************/

/*************************************************************************/
/* その他の定義                                                          */
/*************************************************************************/

/*************************************************************************/
/* 大域変数宣言                                                          */
/*************************************************************************/
static SCI_BUFFER *sci_snd[ 5 ];
static SCI_BUFFER *sci_rcv[ 5 ];

/*************************************************************************/
/* プロトタイプ宣言                                                      */
/*************************************************************************/
static SCI_REG *Select_SCI( int ch );

/*************************************************************************/
/* SCI(USART)初期化                                                      */
/*************************************************************************/
static SCI_REG *Select_SCI( int ch )
{
  switch ( ch )
  {
    case SCI_1 : return (SCI_REG *)USART1;
    case SCI_2 : return (SCI_REG *)USART2;
    case SCI_3 : return (SCI_REG *)USART3;
    case SCI_4 : return (SCI_REG *)USART4;
    case SCI_5 : return (SCI_REG *)USART5;
    default : break;
  }

  return (SCI_REG *)0;
}

/*************************************************************************/
/* SCI(USART)初期化                                                      */
/*************************************************************************/
int SCI_Init( int ch, SCI_BUFFER *rcv, SCI_BUFFER *snd, unsigned long brr )
{
  NVIC_InitTypeDef NVIC_InitStructure;
  SCI_REG *sci = Select_SCI( ch );

  if( sci == (SCI_REG *)0 ) return (-1);

  sci_rcv[ ch ] = rcv;
  sci_snd[ ch ] = snd;

  switch ( ch )
  {
    case SCI_1 :
      AFIO_MAPR &= 0xfffffffb;
      PA_CRH &= 0xfffff00f;  /*pa9=tx,pa10=rx*/
      PA_CRH |= 0x000004b0;
      /*USART1へクロックの供給開始*/
      RCC_APB2PeriphClockCmd( RCC_APB2Periph_USART1, ENABLE );
      RCC_APB2PeriphResetCmd( RCC_APB2Periph_USART1, DISABLE );
      /*USART1の割り込み設定*/
      NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQChannel;
      break;

    case SCI_2 :
      AFIO_MAPR |= 0x00000008;  /*pd5,6で使用するにはリマップが必要*/
      PD_CRL &= 0xf00fffff;  /*pd5=tx,pd6=rx*/
      PD_CRL |= 0x04b00000;
      /*USART2へクロックの供給開始*/
      RCC_APB1PeriphClockCmd( RCC_APB1Periph_USART2, ENABLE );
      RCC_APB1PeriphResetCmd( RCC_APB1Periph_USART2, DISABLE );
      /*USART2の割り込み設定*/
      NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQChannel;
      brr /= 2;
      break;

    case SCI_3 :
      AFIO_MAPR &= 0xffffffcf;  /*pd8,9で使用するにはリマップが必要*/
      AFIO_MAPR |= 0x00000030;  /*pd8,9で使用するにはリマップが必要*/
      PD_CRH &= 0xffffff00;  /*pd8=tx,pd9=rx*/
      PD_CRH |= 0x0000004b;
      /*USART3へクロックの供給開始*/
      RCC_APB1PeriphClockCmd( RCC_APB1Periph_USART3, ENABLE );
      RCC_APB1PeriphResetCmd( RCC_APB1Periph_USART3, DISABLE );
      /*USART3の割り込み設定*/
      NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQChannel;
      brr /= 2;
      break;

    case SCI_4 :
      PC_CRH &= 0xffff00ff;  /*pc10=tx,pc11=rx*/
      PC_CRH |= 0x00004b00;
      /*USART4へクロックの供給開始*/
      RCC_APB1PeriphClockCmd( RCC_APB1Periph_USART4, ENABLE );
      RCC_APB1PeriphResetCmd( RCC_APB1Periph_USART4, DISABLE );
      /*USART4の割り込み設定*/
      NVIC_InitStructure.NVIC_IRQChannel = USART4_IRQChannel;
      brr /= 2;
      break;

    case SCI_5 :
      PC_CRH &= 0xfff0ffff;  /*pc12=tx*/
      PC_CRH |= 0x000b0000;
      PD_CRL &= 0xfffff0ff;  /*pd2=rx*/
      PD_CRL |= 0x00000400;
      /*USART5へクロックの供給開始*/
      RCC_APB1PeriphClockCmd( RCC_APB1Periph_USART5, ENABLE );
      RCC_APB1PeriphResetCmd( RCC_APB1Periph_USART5, DISABLE );
      /*USART5の割り込み設定*/
      NVIC_InitStructure.NVIC_IRQChannel = USART5_IRQChannel;
      brr /= 2;
      break;
  }

  sci->cr1 = 0;  /*USART停止*/
  sci->brr = brr;  /*???bps*/
  sci->cr2 = 0;  /**/
  sci->cr3 = EIE_Bit;  /*エラー発生時の割り込み許可*/
  sci->cr1 = UE_Bit | TE_Bit | RE_Bit | RXNEIE_Bit;  /*8bit,1stop bit,parity none,tx enable, rx enable,rxie enable*/

  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x40;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init( &NVIC_InitStructure );

  return 0;
}

/*************************************************************************/
/* SCI一文字送信                                                         */
/*************************************************************************/
int SCI_Putc( int ch, char c )
{
  SCI_REG *sci = Select_SCI( ch );

  if( sci == (SCI_REG *)0 ) return (-1);

  while( !(sci->sr & TXE_Bit) ) ;
  sci->dr = c;

  return 0;
}

/*************************************************************************/
/* SCI文字列送信                                                         */
/*************************************************************************/
int SCI_Puts( int ch, char *str )
{
#if 1
  char *ptr;
  unsigned short next;
  int count;
  SCI_BUFFER *snd;
  SCI_REG *sci;

  if( ch != SCI_1 && ch != SCI_2 && ch != SCI_3 && ch != SCI_4 && ch != SCI_5 ) return (-1);  /**/
  if( SndSizeOfBuf( ch ) == 0 ) return (-1);  /*書き込む余裕が無かった場合*/

  sci = Select_SCI( ch );
  snd = sci_snd[ ch ];  /*バッファの選択*/

  count = 0;
  ptr = (char *)snd->buf;
  while( *str )
  {
    next = snd->wptr + 1;  /*ポインタを進めてみる*/
    if( next >= snd->size ) next = 0;  /*書き込みポインタの丸め*/
    if( next == snd->rptr ) break;  /*代入出来ない時*/
    ptr[ snd->wptr ] = *str++;  /*バッファに代入*/
    sci->cr1 |= TXEIE_Bit;  /*送信割込み許可*/
    count++;  /*書き込んだカウント値を更新*/
    snd->wptr = next;  /*書き込みポインタを進める*/
  }

  return count;
#else
  while( *str ) (void)SCI_Putc( ch, *str++ );
  return 0;
#endif
}

/*************************************************************************/
/* SCI受信バッファの受信サイズ                                           */
/*************************************************************************/
unsigned short RcvSizeOfBuf( int ch )
{
  SCI_BUFFER *rcv;
  unsigned short w,r;

  rcv = sci_rcv[ ch ];  /*バッファの選択*/
  w = rcv->wptr;
  r = rcv->rptr;

  if( w == r ) return 0;
  else if( w < r ) return w + rcv->size - r;
  else return w - r;
}

/*************************************************************************/
/* SCI送信バッファの空きサイズ                                           */
/*************************************************************************/
unsigned short SndSizeOfBuf( int ch )
{
  SCI_BUFFER *snd;
  unsigned short w,r;

  snd = sci_snd[ ch ];  /*バッファの選択*/
  w = snd->wptr;
  r = snd->rptr;

  if( w == r ) return snd->size - 1;
  else if( r < w ) return r + snd->size - w - 1;
  else return r - w - 1;
}

/*************************************************************************/
/* SCI受信バッファから1文字取得                                          */
/*************************************************************************/
int SCI_Getc( int ch )
{
  int c;
  char *buf;
  SCI_BUFFER *rcv;

  rcv = sci_rcv[ ch ];  /*バッファの選択*/
  if( RcvSizeOfBuf( ch ) == 0 ) return (-1);
  buf = (char *)rcv->buf;
  c = buf[ rcv->rptr ];
  if( ++rcv->rptr >= rcv->size ) rcv->rptr = 0;

  return c & 0x00ff;
}

/*************************************************************************/
/* SCIステータスの読み出し                                               */
/*************************************************************************/
unsigned long SCI_Status( int ch )
{
  SCI_REG *sci = Select_SCI( ch );
  return sci->sr;
}

/*************************************************************************/
/* SCIステータスの読み出し                                               */
/*************************************************************************/
char SCI_DirectRead( int ch )
{
  SCI_REG *sci = Select_SCI( ch );
  return sci->dr;
}

/*************************************************************************/
/* SCI色々割り込み                                                       */
/* どうも要因別の割り込みは無いみたいだな                                */
/*************************************************************************/
void SCI_ISR( int ch )
{
  unsigned short next;
  volatile unsigned long status;
  char data,*ptr;
  SCI_REG *sci = Select_SCI( ch );
  SCI_BUFFER *rcv;
  SCI_BUFFER *snd;

  status = sci->sr;
  /*各種エラーのチェック*/
  if( status & (FE_Bit | PE_Bit | NE_Bit | ORE_Bit) )
  {
    data = sci->dr;  /*エラーステータスを解除する為にはデータレジスタの読み込みが必要*/
    return;
  }

  /*受信割り込みの判定*/
  if( status & RXNE_Bit )
  {
    data = sci->dr;  /**/
    rcv = sci_rcv[ ch ];  /*バッファの選択*/
    ptr = (char *)rcv->buf;
    next = rcv->wptr + 1;
    if( next >= rcv->size ) next = 0;
    if( next == rcv->rptr ) return;  /*上書きは禁止されるので、入らない分は破棄*/
    *(ptr + rcv->wptr) = data;
    rcv->wptr = next;
  }

  /*送信割り込みの判定*/
  if( status & TXE_Bit )
  {
    snd = sci_snd[ ch ];  /*バッファの選択*/
    if( snd->rptr == snd->wptr )  /*送信すべきデータが無い時*/
    {
      sci->cr1 &= ~TXEIE_Bit;  /*送信割込み禁止*/
      return;
    }
    ptr = (char *)snd->buf;
    sci->dr = *(ptr + snd->rptr);
    if( ++snd->rptr >= snd->size ) snd->rptr = 0;
  }
}

/*************************************************************************/
/* end of file                                                           */
/*                                 designed by hamayan since 2008/11/06  */
/*************************************************************************/


stm32f10x_it.cの割込み処理のところ
/*******************************************************************************
* Function Name  : USART1_IRQHandler
* Description    : This function handles USART1 global interrupt request.
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
void USART1_IRQHandler(void)
{
  SCI_ISR( SCI_1 );
}








nice!(0)  コメント(1)  トラックバック(0) 

nice! 0

コメント 1

todotani

遅レスですが、、
ちょうどSTM32 Primer2でUSARTを割り込みベースで動かそうと思っていましたので参考にさせていただきます。送受信バッファ制御のコードはそのまま拝借するかもです。
Primer2では割り込みベクターがCircleOS管理になっているため(RAMにテーブルを移動しています)、一部CircleOS依存の独自コードになってしまいます。ただ、色々便利な機能(FAT FSやLCD表示など)提供してくれるためついつい堕落して一から作るのをさぼってしまいます。
by todotani (2009-10-08 21:00) 

コメントを書く

お名前:[必須]
URL:
コメント:
画像認証:
下の画像に表示されている文字を入力してください。

※ブログオーナーが承認したコメントのみ表示されます。

トラックバック 0

この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。