So-net無料ブログ作成

STM32CubeMXに関する事 4 CoIDEで開発 4 [STM32F]

STM32CubeMXコードジェネレータの出力を、CoIDE環境で動かしたい!と言う話
makeCubeMxProjectForCoIDE_028.png


前回まではCoIDEで生成したコードを取り込みました。
今回はLEDチカチカを記述していきます。
1.STM32CubeMXの出力にはサンプルが含まれていないので、生成されたコードの使い方がイマイチ判りません。
STマイクロのサイトに行って、このファイルを落としてくると周辺機能ごとのサンプルが有りますので、これを参照します。
http://www.st.com/en/embedded-software/stm32cube-embedded-software.html?querycriteria=productId=LN1897
makeCubeMxProjectForCoIDE_024.png


2.先ほどのPC6にラベル付けを行った定義はmain.hに、初期化コードはmain.cに書かれています。
makeCubeMxProjectForCoIDE_025.png


makeCubeMxProjectForCoIDE_026.png


3.mainのwhileループの中にチカチカを書いてみました。
HAL_GPIO_WritePinはstm32f1xx_hal_gpio.hに、HAL_Delayはstm32f1xx_hal.hに宣言されていますが、なぜかHAL_Delayにはエラー表示が、、、
makeCubeMxProjectForCoIDE_027.png


makeCubeMxProjectForCoIDE_030.png


4.デバッガーを起動して、今回はREMAPによるデバッガーの暴走は発生しませんでした(笑)。
makeCubeMxProjectForCoIDE_031.png




たぶん続く。

STM32マイコン徹底入門 (TECH I Processor)

STM32マイコン徹底入門 (TECH I Processor)

  • 作者: 川内 康雄
  • 出版社/メーカー: CQ出版
  • 発売日: 2010/10/29
  • メディア: 単行本






nice!(0)  コメント(0) 

STM32CubeMXに関する事 4 CoIDEで開発 3 [STM32F]

STM32CubeMXコードジェネレータの出力を、CoIDE環境で動かしたい!と言う話
makeCubeMxProjectForCoIDE_028.png


前回まではSTM32CubeMXを使ってコード生成しました。
今回はCoIDEで生成したコードを取り込みます。
1.STM32CubeMXの出力先に、先に生成したCoIDEのプロジェクトフォルダーを指定したためか、C Libraryとかセミホスティングのコードが削除されてしまいました。諦めてもう一度リポジトリから追加します。
また、ファイルエクスプローラからドラッグ&ドロップでCoIDEのプロジェクトツリーに
Drivers、Inc、Src、startupの4つを放り込みます。
makeCubeMxProjectForCoIDE_018.png


2.CoIDEの設定(Configuration)タブを開き、Compileタブから設定します。赤枠の定義を追加します。
makeCubeMxProjectForCoIDE_021.png


3.Linkタブでオプションを赤枠の通りに、リンカースクリプトをTrueIDE用に生成されたスクリプトを選択します。
makeCubeMxProjectForCoIDE_019.png


4.DebuggerタブでSWDとなっている事を確認します。セミホスティングを使う場合はSemiHosting enableにチェック
makeCubeMxProjectForCoIDE_023.png


5.ビルドするとエラーが出ます(笑)。
セミホスティング機能を追加した時に追加されたファイルのsh_cmd.sのHardFault_Handlerがぶつかっている為です。プロジェクトから削除してしまいます。
makeCubeMxProjectForCoIDE_020.png


嘘です。sh_cmd.sを削除するのではなく、sh_cmd.sの15行目辺りのglobal宣言をコメントアウトします。こんな風に。
/*.global HardFault_Handler*/



またまた長いので続く。

STM32マイコン徹底入門 (TECH I Processor)

STM32マイコン徹底入門 (TECH I Processor)

  • 作者: 川内 康雄
  • 出版社/メーカー: CQ出版
  • 発売日: 2010/10/29
  • メディア: 単行本






nice!(0)  コメント(0) 

STM32CubeMXに関する事 4 CoIDEで開発 2 [STM32F]

STM32CubeMXコードジェネレータの出力を、CoIDE環境で動かしたい!と言う話
makeCubeMxProjectForCoIDE_028.png


前回まではCoIDEでプロジェクトを新規生成しました。
今回はSTM32CubeMXを使ってコード生成します。

1.STM32CubeMXを起動して
makeCubeMxProjectForCoIDE_006.png


2.ポチポチとマイコンを選択
makeCubeMxProjectForCoIDE_007.png


3.PIN配置の画面が開く
makeCubeMxProjectForCoIDE_008.png


4.マイコンのICの足をクリックすると、この端子の機能が選択できるようになる。今回はGPIOの出力に設定。また左のペインのSYSを展開してデバッガ機能としてSWDを有効化。
makeCubeMxProjectForCoIDE_009.png


5.RCC、RTC等はクロックソースに応じて有効化。
makeCubeMxProjectForCoIDE_011.png


6.クロックの設定のタブを開き、クロックソースとか、倍率を設定。今回は外部に8Mのクリスタルを実装している事から、このマイコンの最大の72MHzで動くように設定。
makeCubeMxProjectForCoIDE_012.png


MB-STM32-mpu_sch.jpg


7.設定のタブでGPIOをクリックし、LEDを接続してあるPC6に適当なラベルを付加
makeCubeMxProjectForCoIDE_014.png


makeCubeMxProjectForCoIDE_013.png


8.電力計算機能の使い方はよく判らんので、スルー。
makeCubeMxProjectForCoIDE_015.png


9.生成するプロジェクトの名前などの設定。ToolchainはTrueIDEを選択している。
makeCubeMxProjectForCoIDE_016.png


10.生成するプロジェクトの生成コードに関する設定。必要な機能のみ生成と未接続の端子をアナログ扱い?
makeCubeMxProjectForCoIDE_017.png


11.コードの生成を行う。また、コード生成プロジェクト自身を適当なフォルダーに保存。
makeCubeMxProjectForCoIDE_029.png


makeCubeMxProjectForCoIDE_010.png




またまた長いので続く。

ARMマイコンCortex-M教科書 (ARM教科書)

ARMマイコンCortex-M教科書 (ARM教科書)

  • 作者: 桑野 雅彦 共著 中森 章
  • 出版社/メーカー: CQ出版
  • 発売日: 2016/11/21
  • メディア: 単行本



STM32マイコン徹底入門 (TECH I Processor)

STM32マイコン徹底入門 (TECH I Processor)

  • 作者: 川内 康雄
  • 出版社/メーカー: CQ出版
  • 発売日: 2010/10/29
  • メディア: 単行本



nice!(0)  コメント(0) 

STM32CubeMXに関する事 4 CoIDEで開発 1 [STM32F]

STM32CubeMXコードジェネレータの出力を、CoIDE環境で動かしたい!と言う話
makeCubeMxProjectForCoIDE_028.png


まずCoIDEでプロジェクトを新規生成します。ターゲットはAitendoのSTM32F103VE基板(MB-STM32F103)、なんと引っ越し価格?で一枚999円だす。
※ただしUSB/シリアルのPL-2303HXのドライバがWindows10に対応していないくて、ちょっとだけ苦労します。ここを参照-> http://www.ifamilysoftware.com/news37.html
mb-stm32f103_001.jpg


このボードには4つのLEDが実装されています。接続はこんな感じです。って、回路図が断片化したjpegファイルしか無くてつらい、、、
MB-STM32-led_sch.jpg


PC6に接続されているLED、D1をチカチカさせてみましょう。

1.CoIDEで新規プロジェクトを作成開始
makeCubeMxProjectForCoIDE_001.png


2.CHIPを選択
makeCubeMxProjectForCoIDE_002.png


3.STM32F103VEを選択
makeCubeMxProjectForCoIDE_003.png


4.リポジトリで最低限の機能を追加。欲しいのはC Libraryと、デバック用にセミホスティング
※とは言え、後程Stm32CubeMXを動かすと無残にも削除?されてしまうので、何も選択しなくてもいいのかも、、、
makeCubeMxProjectForCoIDE_004.png


5.main.cとか要らないので、、、フォルダーとプロジェクトから削除、
makeCubeMxProjectForCoIDE_005.png



長いので続く!

ディジタル回路設計とコンピュータアーキテクチャ[ARM版]

ディジタル回路設計とコンピュータアーキテクチャ[ARM版]

  • 作者: デイビッド・M・ハリス サラ・L・ハリス
  • 出版社/メーカー: 星雲社
  • 発売日: 2016/04/25
  • メディア: 大型本



STM32マイコン徹底入門 (TECH I Processor)

STM32マイコン徹底入門 (TECH I Processor)

  • 作者: 川内 康雄
  • 出版社/メーカー: CQ出版
  • 発売日: 2010/10/29
  • メディア: 単行本



nice!(0)  コメント(0) 

STM32CubeMXに関する事 3 クロックツリー [STM32F]

STM32CubeMXコードジェネレータのこういうのは、本当にイイねー!
新人君へのクロック系統の説明にもとても役に立った。
stm32cubemx_002.png


nice!(1)  コメント(0) 

STM32CubeMXに関する事 2 リングバッファではないだと、、、 [STM32F]

STM32CubeMXコードジェネレータが出力するUART(USART)のコードについて。
mb-stm32f103_001.jpg

以下の様な送信/受信関数が提供されます。
HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout);
HAL_StatusTypeDef HAL_UART_Receive(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout);
HAL_StatusTypeDef HAL_UART_Transmit_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);
HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);
HAL_StatusTypeDef HAL_UART_Transmit_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);
HAL_StatusTypeDef HAL_UART_Receive_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);

HAL_UART_Transmit、HAL_UART_Receiveはブロッキングインタフェースで、内部で送信レジスタ、受信レジスタを監視して動作していますが、それ以下の関数は割り込みとDMAを併用するノンブロッキングインタフェースとなっています。

それぞれの関数は、引数のデータ数に送信や受信が達する事で完了となります。
それ以前に再びこの関数が呼ばれた時は、戻り値にHAL_BUSYが返ります。

つまり問題は受信時に処理を完了させる要素が引数の受信データ数となっている点ですね。
送信はイイのですよ、事前に送信データのサイズは明確にできますから。
ですが受信の場合相手がいる訳ですから、実際に受信するデータの数が事前に判る状況はあまり無いでしょう。

100byteデータを受信するとなっても、通信ですから途中でなにが起こるか判らない。
受信サイズを100byteとしてしまって途中で1byteこけた場合はそのまま処理が永久に?完了しない事となります。

ブロッキングインタフェースの場合は引数にタイムアウトを設定できるので、タイムアウトを使う事でプログラムが不動となる事は避けられそうです。

しかしノンブロッキングインタフェースではタイムアウトは設定されていないので、1byteでも受信数が少ない場合は不動となる可能性が有ります。


逆に言えば受信データ数には1を超える数字を設定しなければイイ!と言う、高機能な関数を消極的な使い方をすれば解決できそうです、、、orz
ついでにリングバッファを構成しましょう。

※usart1とusart2を使えるようにした。
※USARTのコンフィギュレーションは別のところで行ってる。
※includeなどは省いている。
※usart2はループバック、usart1はTeratermに接続している。
HAL_StatusTypeDef usartWrite( UART_HandleTypeDef *huart, const uint8_t *data, uint16_t size );
HAL_StatusTypeDef usartPutc( UART_HandleTypeDef *huart, char c );
HAL_StatusTypeDef usartPuts( UART_HandleTypeDef *huart, const char *str );
int usartGetc( UART_HandleTypeDef *huart );
int usartAvailable( UART_HandleTypeDef *huart );

static struct  P_USART_RCV_INFORMATIONS
{
  char *rcvBuf;
  uint16_t wptr,rptr;
  uint16_t overWrite;
  uint16_t bufferSize;
} pUsartRcvInfo[2];

static char rx1Buffer[ 256 ];  /* recieve ring buffer. */
static char rx2Buffer[ 256 ];  /* recieve ring buffer. */

void user( void )
{
  volatile int count = 1;
  HAL_StatusTypeDef result;

  pUsartRcvInfo[0].rcvBuf = rx1Buffer;
  pUsartRcvInfo[0].wptr = pUsartRcvInfo[0].rptr = pUsartRcvInfo[0].overWrite = 0;
  pUsartRcvInfo[0].bufferSize = sizeof(rx1Buffer);
  pUsartRcvInfo[1].rcvBuf = rx2Buffer;
  pUsartRcvInfo[1].wptr = pUsartRcvInfo[1].rptr = pUsartRcvInfo[1].overWrite = 0;
  pUsartRcvInfo[1].bufferSize = sizeof(rx2Buffer);

  HAL_UART_Receive_IT( &huart1, (uint8_t *)&pUsartRcvInfo[0].rcvBuf[ pUsartRcvInfo[0].wptr ], 1 );
  HAL_UART_Receive_IT( &huart2, (uint8_t *)&pUsartRcvInfo[1].rcvBuf[ pUsartRcvInfo[1].wptr ], 1 );

  while (1)
  {
    char buf[128];
    sprintf( buf, "hello world. count = %d\r\n", count++ );

    result = usartPuts( &huart2, (const char *)buf );
    if( result != HAL_OK )
    {
      debugPrint( "uart2 transmit was not success. error code = %d\r\n", result );
    }

    HAL_Delay( 10UL );
    while( 1 )
    {
      int c = usartGetc( &huart2 );
      if( c < 0 ) break;
      usartPutc( &huart1, c );
    }

    HAL_Delay( 90UL );
  }
}

HAL_StatusTypeDef usartWrite( UART_HandleTypeDef *huart, const uint8_t *data, uint16_t size )
{
  HAL_StatusTypeDef result;

  //while( (result = HAL_UART_Transmit( huart, (uint8_t *)data, size, 100UL )) == HAL_BUSY ) {}
  while( (result = HAL_UART_Transmit_IT( huart, (uint8_t *)data, size )) == HAL_BUSY ) {}
  return result;
}

HAL_StatusTypeDef usartPutc( UART_HandleTypeDef *huart, char c )
{
  return usartWrite( huart, (const uint8_t *)&c, 1 );
}

HAL_StatusTypeDef usartPuts( UART_HandleTypeDef *huart, const char *str )
{
  return usartWrite( huart, (const uint8_t *)str, strlen(str) );
}

int usartGetc( UART_HandleTypeDef *huart )
{
  int c;
  uint16_t next;
  if( huart->Instance == USART1 )
  {
    if( pUsartRcvInfo[0].rptr == pUsartRcvInfo[0].wptr ) return (-1);  /*  */

    next = pUsartRcvInfo[0].rptr + 1;
    if( next >= pUsartRcvInfo[0].bufferSize ) next = 0;
    c = pUsartRcvInfo[0].rcvBuf[ pUsartRcvInfo[0].rptr ] & 0x00ff;
    pUsartRcvInfo[0].rptr = next;
  }
  else if( huart->Instance == USART2 )
  {
    if( pUsartRcvInfo[1].rptr == pUsartRcvInfo[1].wptr ) return (-1);  /*  */

    next = pUsartRcvInfo[1].rptr + 1;
    if( next >= pUsartRcvInfo[1].bufferSize ) next = 0;
    c = pUsartRcvInfo[1].rcvBuf[ pUsartRcvInfo[1].rptr ] & 0x00ff;
    pUsartRcvInfo[1].rptr = next;
  }
  return c;
}

int usartAvailable( UART_HandleTypeDef *huart )
{
  if( huart->Instance == USART1 )
  {
    if( pUsartRcvInfo[0].wptr >= pUsartRcvInfo[0].rptr )
    {
      return pUsartRcvInfo[0].wptr - pUsartRcvInfo[0].rptr;
    }
    else
    {
      return (pUsartRcvInfo[0].bufferSize + pUsartRcvInfo[0].wptr) - pUsartRcvInfo[0].rptr;
    }
  }
  else if( huart->Instance == USART2 )
  {
    if( pUsartRcvInfo[1].wptr >= pUsartRcvInfo[1].rptr )
    {
      return pUsartRcvInfo[1].wptr - pUsartRcvInfo[1].rptr;
    }
    else
    {
      return (pUsartRcvInfo[1].bufferSize + pUsartRcvInfo[1].wptr) - pUsartRcvInfo[1].rptr;
    }
  }
  return 0;
}



#if 0
/**
  * @brief  Tx Transfer completed callbacks.
  * @param  huart: pointer to a UART_HandleTypeDef structure that contains
  *                the configuration information for the specified UART module.
  * @retval None
  */
void HAL_UART_TxCpltCallback( UART_HandleTypeDef *huart )
{
}
#endif


/**
  * @brief  Rx Transfer completed callbacks.
  * @param  huart: pointer to a UART_HandleTypeDef structure that contains
  *                the configuration information for the specified UART module.
  * @retval None
  */
void HAL_UART_RxCpltCallback( UART_HandleTypeDef *huart )
{
  uint16_t next;
  if( huart->Instance == USART1 )
  {
    next = pUsartRcvInfo[0].wptr + 1;
    if( next >= pUsartRcvInfo[0].bufferSize ) next = 0;
    if( next == pUsartRcvInfo[0].rptr )  /* do not permit over write. */
    {
      pUsartRcvInfo[0].overWrite++;
      return;
    }
    pUsartRcvInfo[0].wptr = next;
    HAL_UART_Receive_IT( huart, (uint8_t *)&pUsartRcvInfo[0].rcvBuf[ pUsartRcvInfo[0].wptr ], 1 );
  }
  else if( huart->Instance == USART2 )
  {
    next = pUsartRcvInfo[1].wptr + 1;
    if( next >= pUsartRcvInfo[1].bufferSize ) next = 0;
    if( next == pUsartRcvInfo[1].rptr )  /* do not permit over write. */
    {
      pUsartRcvInfo[1].overWrite++;
      return;
    }
    pUsartRcvInfo[1].wptr = next;
    HAL_UART_Receive_IT( huart, (uint8_t *)&pUsartRcvInfo[1].rcvBuf[ pUsartRcvInfo[1].wptr ], 1 );
  }
}


nice!(0)  コメント(0) 

STM32CubeMXに関する事 1 デバッグできん! [STM32F]

さて、STマイクロのSTM32Fシリーズでは、従来はSPLライブラリが提供されてたのですが、最近リリースされるマイコンにはSPLライブラリは提供されず、代わりにSTM32CubeMXと言うコードジェネレータを使え!となっているので、しょうがないので触り始めて嵌っています、、、orz

今回の問題は、STM32CubeMXが出力するREMAPに関するマクロです。
ターゲットはSTM32F103VETです。
嵌ったのはI2Cを有効にするとデバッガーが暴走する!ってものでした。

くだんのマクロ集の抜粋です。( stm32f1xx_hal_gpio_ex.h )
/**
  * @brief Enable the remapping of I2C1 alternate function SCL and SDA.
  * @note  ENABLE: Remap     (SCL/PB8, SDA/PB9)
  * @retval None
  */
#define __HAL_AFIO_REMAP_I2C1_ENABLE()  SET_BIT(AFIO->MAPR, AFIO_MAPR_I2C1_REMAP)

SET BITは以下 ( stm32f1xx.h )
/** @addtogroup Exported_macros
  * @{
  */
#define SET_BIT(REG, BIT)     ((REG) |= (BIT))

#define CLEAR_BIT(REG, BIT)   ((REG) &= ~(BIT))

#define READ_BIT(REG, BIT)    ((REG) & (BIT))

#define CLEAR_REG(REG)        ((REG) = (0x0))

#define WRITE_REG(REG, VAL)   ((REG) = (VAL))

#define READ_REG(REG)         ((REG))

#define MODIFY_REG(REG, CLEARMASK, SETMASK)  WRITE_REG((REG), (((READ_REG(REG)) & (~(CLEARMASK))) | (SETMASK)))

#define POSITION_VAL(VAL)     (__CLZ(__RBIT(VAL))) 

つまりRead Modify Writeをします。

ところがSTM32F103のREMAPを制御しているMAPRレジスタの説明にはこの様に書かれています。
stm32cubemx_001.png


なので、読み出しても正確な値ではない!

じっさいのところこのマクロを処理するとデバッグできなくなるので、逆アセンブルしてレジスタを追ってみると
100: JTAG-DP Disabled and SW-DP Disabled
が入ってきてしまいます。これでは動きませんよね、、、

対策はREMAPを行っているところでは必ず後ろに
__HAL_AFIO_REMAP_SWJ_NOJTAG();
などのデバッガを有効にするマクロを追加する?

( stm32f1xx_hal_msp.c )
void HAL_I2C_MspInit(I2C_HandleTypeDef* hi2c)
{

  GPIO_InitTypeDef GPIO_InitStruct;
  if(hi2c->Instance==I2C1)
  {
  /* USER CODE BEGIN I2C1_MspInit 0 */

  /* USER CODE END I2C1_MspInit 0 */
  
    /**I2C1 GPIO Configuration    
    PB8     ------> I2C1_SCL
    PB9     ------> I2C1_SDA 
    */
    GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_9;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

    //__HAL_AFIO_REMAP_I2C1_ENABLE();  // <------  訂正:コメントアウト
   // __HAL_AFIO_REMAP_SWJ_NOJTAG();  // <------  訂正:コメントアウト

    /* Peripheral clock enable */
    __HAL_RCC_I2C1_CLK_ENABLE();
  /* USER CODE BEGIN I2C1_MspInit 1 */
    uint32_t mapr = AFIO->MAPR;      // <------  訂正:マクロをやめて直接レジスタを操作
    mapr &= ~(7UL << 24);
    mapr |= (2UL << 24);
    mapr |= (1UL << 1);
    AFIO->MAPR = mapr;
  /* USER CODE END I2C1_MspInit 1 */
  }
}


しかしCubeMXでコードを生成する度にこの対策が消されてしまうのでは?と思っています、、、ハァ。

nice!(0)  コメント(0) 

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