So-net無料ブログ作成

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) 

ネット越しにオシロを操作 [電子工作]

入手したテクトロのTDS3034B
tds3034b_002.jpg

テクトロのオシロは、わりと操作が直感的にできる点がイイよね。ただ、波形はあまり綺麗ではない気がする。

だいぶ前に作ったTDS3034B用のアプリケーション。
tds3034b_001.png

TDS3034BとかTDS3034Cを遠隔で操作する為に作成した。開発環境がVS2010のC#だから5年以上前に作成。
このアプリを作る為にC#を勉強したが、もうC#忘れたがな!www

※TDS3034BとTDS3034Cでは微妙にネットワークのインタフェース仕様が異なっていて困った(笑)

写真のオシロはSCALEツマミが正常に動かないので、ちょうど作成したアプリが役に立っている。
なんでも作ってみるもんだねぇ!

2次選考落選!www GRデザインコンテスト2016応募作品 赤外線追尾型ペットカメラ [XBee]

petCamera001.jpg

RL78/G13とXBee、2MピクセルJPEGカメラ、サーモセンサー、SDカード、LED照明、サーボモーター等々で作った作品。

これで最近いたずらが酷いまきおの様子も撮影して、動かぬ証拠にできるかも!
petCamera004.jpg







SG90サーボ用 2軸 カメラマウント 2軸アングル FPV 空撮にも (マウント+2個SG90)

SG90サーボ用 2軸 カメラマウント 2軸アングル FPV 空撮にも (マウント+2個SG90)

  • 出版社/メーカー: サンクスワールド
  • メディア: おもちゃ&ホビー






Lazurite 920Jを立ち上げてみる 其の10 #LAZURITE920J #ラピスセミコンダクタ [Lazurite]

lazuriteImage_003.jpg
変換基板の配布をしようと思っています。数量は20~30セットくらい。

いやぁ、某店舗での委託販売で交渉をしていましたが、「常時在庫を持つ!」「1年間の継続販売必須!」と言う事で売り切りができず、個人ではもっとも辛いところの在庫を持つ!必要があり、いまのところ断念しています。

セット内容は、基板と1.27mmピッチのコネクタ、2mmピッチ、2.54mmピッチのコネクタになります。

価格ですが、委託販売を行わない事から某店への手数料などが無くなるので、1000円ポッキリを考えています。※送料は別です!

どうでしょうかね?
※勿論サポートもここで行います。
※好評?だったら別タイプの変換基板も企画を進めます。

コメントに書いていただくか、以下から連絡先のファイルを入手してください。
https://dl.dropboxusercontent.com/u/60463387/contact/contact.txt

※変換基板と言えば、ESP8266をXBeeのピン配置に変換する基板も用意しているんですよ。でも半田付け、結構大変です。こちらも良かったら要望を送ってください。
ESP8266_BEE.jpg

Lazurite 920Jを立ち上げてみる 其の9 #LAZURITE920J #ラピスセミコンダクタ [Lazurite]

lazuriteImage_025.png

マルチタスクで行こう!

例によってマルチタスク化。例によってノンプリエンプティブ。


〇ドキュメントの在処
ネットを検索しても見つからないなぁ、、、と思っていたら、東大元暮らしでした!
ついついネット上に有ると思い込んでしまいますね。

▼FJUL-U16-100-INST-02.pdf
アーキテクチャの解説とアセンブラ命令コードの解説

▼FJXTCCU8_UM-08.pdf
コンパイラ・ユーザーズマニュアル

▼FJXTCCU8_PG-03.pdf
コンパイラ・プログラミングガイド

▼FJXTCCU8_LR-03.pdf
コンパイラ・ランゲージリファレンス


〇CPUについてまとめると
▼16bit RISCマイコン、記述が見つからなかったけれどハーバードアーキテクチャかもしれない。
一応1命令1クロック。

▼3段パイプライン。パイプラインストールを頻発しなければ結構速いかもしれない。

▼メモリ空間に関してsmallモデルとLargeモデルが有るが、今回はsmallモデルを対象としている。
ROM 64kbyte、RAM 6kbyte


〇ディスパッチャーを作る
どうでもイイことを勘違いして一日悩んだが、smallモデルであればわりと簡単だと思う。
/****************************************************************************/
/* dispatcher                                                               */
/****************************************************************************/
void sta_ctx( void *exe )  /*exe=ER0*/
{
  __asm( "L ER2,[ER0]\n" );  /**/
  __asm( "MOV SP,ER2\n" );  /**/

  __asm( "POP QR8\n" );  /*R8-R15 8bytes*/
  __asm( "POP XR4\n" );  /*R4-R7 4bytes*/
  __asm( "POP LR\n" );  /*link register 2bytes*/
}

void swi_ctx( void *pre, void *post )  /*pre=ER0,post=ER2*/
{
  __asm( "PUSH LR\n" );  /*link register*/
  __asm( "PUSH XR4\n" );  /*R4-R7*/
  __asm( "PUSH QR8\n" );  /*R8-R15*/

  __asm( "MOV ER4,SP\n" );  /**/
  __asm( "ST ER4,[ER0]\n" );  /**/

  __asm( "L ER0,[ER2]\n" );  /**/
  __asm( "MOV SP,ER0\n" );  /**/

  __asm( "POP QR8\n" );  /*R8-R15*/
  __asm( "POP XR4\n" );  /*R4-R7*/
  __asm( "POP LR\n" );  /*link register*/
}



〇サンプルプログラム
lazuriteImage_028.png

黄色タスクが250ms周期、青タスクが500ms周期、赤タスクが1000ms周期でLEDを点滅させているだけのプログラム
#include "multiTaskDemo_ide.h"		// Additional Header
#include  <mul_tsk.h>
#include "delivertive.h"

#define  BLUE_LED       26
#define  RED_LED        20
#define  YELLO_LED      25

void led_yello( void );
void led_blue( void );
void led_red( void );

char tsk1_stk[ 256 ];
char tsk2_stk[ 256 ];
char tsk3_stk[ 256 ];

void tsk_ini( void )
{
  reg_tsk( ID_led_yello,led_yello, tsk1_stk, sizeof(tsk1_stk), (VP_INT)0,(VP_INT)0,(VP_INT)0,(VP_INT)0 );
  reg_tsk( ID_led_blue, led_blue, tsk2_stk, sizeof(tsk2_stk), (VP_INT)0,(VP_INT)0,(VP_INT)0,(VP_INT)0 );
  reg_tsk( ID_led_red,  led_red, tsk3_stk, sizeof(tsk3_stk), (VP_INT)0,(VP_INT)0,(VP_INT)0,(VP_INT)0 );

  sta_tsk( ID_led_yello );
  sta_tsk( ID_led_blue );
  sta_tsk( ID_led_red );
}

void setup(void)
{
  Serial.begin( 115022UL );

  tsk_ini();  //タスクの初期化
  sta_rdq( ID_led_yello );  /*ラウンドロビン開始*/
}

// Arduino loop sequence
void loop(void)
{
}

void led_yello( void )
{
  pinMode( YELLO_LED, OUTPUT );
  digitalWrite( YELLO_LED, LOW );
  while( 1 )
  {
    digitalWrite( YELLO_LED, HIGH );
    dly_tsk( 125UL );
    digitalWrite( YELLO_LED, LOW );
    dly_tsk( 125UL );
    Serial.print( "task1 time=" );
    Serial.print_long( millis(), DEC );
    Serial.println( "ms" );
  }
}

void led_blue( void )
{
  pinMode( BLUE_LED, OUTPUT );
  digitalWrite( BLUE_LED, LOW );
  while( 1 )
  {
    digitalWrite( BLUE_LED, HIGH );
    dly_tsk( 250UL );
    digitalWrite( BLUE_LED, LOW );
    dly_tsk( 250UL );
    Serial.print( "task2 time=" );
    Serial.print_long( millis(), DEC );
    Serial.println( "ms" );
  }
}

void led_red( void )
{
  pinMode( RED_LED, OUTPUT );
  digitalWrite( RED_LED, LOW );
  while( 1 )
  {
    digitalWrite( RED_LED, HIGH );
    dly_tsk( 500UL );
    digitalWrite( RED_LED, LOW );
    dly_tsk( 500UL );
    Serial.print( "task3 time=" );
    Serial.print_long( millis(), DEC );
    Serial.println( "ms" );
  }
}


※IDEにプロジェクトの設定ファイルってのがあるんだけれど、ここに書きこんだからと言ってコンパイルオプションに展開されるわけではなく、悲しかった。

※ライブラリのデバックをしたくてSerial.printって書いても、「何それ?美味しいの?」ってコンパイラに言われて、悲しかった。

Lazurite 920Jを立ち上げてみる 其の7 #LAZURITE920J #ラピスセミコンダクタ [Lazurite]

lazuriteImage_004.jpg

まず言って置きます。LazuriteのI2Cの標準の速度は400kHzだぁ。つまずく事間違いなし。勿論私もつまづいた!
※setupの中で100kHzに落としてねー!

さて今日のお題はArudinoとかGR-KURUMIとか用に作成したライブラリの移植の話。

LazuriteはC++をサポートしていないので、ライブラリは全てCソースで記述しなければならない。
この辺を参照して欲しい。
http://hamayan.blog.so-net.ne.jp/2016-10-17

つまりArduinoのライブラリを持って来てもコンパイルすら通らないので、地道にコツコツCソースへの置き換えが必要となる。きっとここでめげる人多数、、、

とは言え買っちゃったのでなんとか使いこなす必要性から、なんとかしてみたいと思う。

今回移植するライブラリはGR-KURUMI用に作成したOLED表示器のライブラリです。
※ArduinoのライブラリをGR-KURUMIに持ってきた場合、かなりの確率でそのまま動く。修正が必要となったとしても、それ程手間ではない。

以下にGR-KURUMI用のソースを掲載します。
US2066.cpp ※<とか>などhtmlに変換した時に正しく変換されていない可能性が有るので、使わない事。
/*********************************************************************************/
/* US2066を使用したOLED SO1602AWGBの初期化と表示                                 */
/*                                         designed by hamayan since 2015/04/21  */
/*********************************************************************************/
#include  <RLduino78.h>
#include  <iodefine.h>
#include  <iodefine_ext.h>
#include  <US2066.h>

extern "C" {
  #include  <mul_tsk.h>
}

#if !defined( _MULTITASK_H_ )
#define  dly_tsk(tim)  delay(tim)
#define  rot_rdq()
#define  loc_cpu()     interrupts()
#define  unl_cpu()     noInterrupts()
#endif /*_MULTITASK_H_ */

US2066::US2066()
{
}

/****************************************************************************/
/* I2C block Write                                                          */
/****************************************************************************/
int US2066::blkWrite(unsigned char addr, const unsigned char *dat, unsigned int len)
{
  Wire.beginTransmission(addr);
  Wire.write(dat,len);
  return Wire.endTransmission();
}

/*************************************************************************/
/* write command         */
/*************************************************************************/
int US2066::writeCommand(unsigned char t_command)
{
  unsigned char cmd[2];

  cmd[0] = 0x00;
  cmd[1] = t_command;

  return blkWrite( i2cAddress, cmd, sizeof(cmd) );
}

/*************************************************************************/
/* write data                                                            */
/*************************************************************************/
int US2066::writeData(unsigned char t_data)
{
  unsigned char dat[2];

  dat[0] = 0x40;
  dat[1] = t_data;

  return blkWrite( i2cAddress, dat, sizeof(dat) );
}

/*************************************************************************/
/* US2066初期化                                                          */
/*************************************************************************/
void US2066::init( unsigned char adr )
{
  i2cAddress = adr;  /*I2C address set*/

  dly_tsk(100);
  writeCommand( 0x01 );  //clear display
  dly_tsk(20);
  writeCommand( 0x02 );  //return home
  dly_tsk(2);
  writeCommand( 0x0f );  //send display on command
  dly_tsk(2);
  writeCommand( 0x01 );  //clear display
  dly_tsk(20);
}

/*************************************************************************/
/* clear display                                                         */
/*************************************************************************/
void US2066::clear( void )
{
  dly_tsk(100);
  writeCommand( 0x01 );  //clear display
  dly_tsk(20);
}

/*************************************************************************/
/* display on/off                                                        */
/*************************************************************************/
void US2066::OnOff( unsigned char onoff )
{
  writeCommand( onoff | 0x08 );  //display on/off,cursor on/off,blink on/off
  dly_tsk(20);
}

/*************************************************************************/
/* locate                                                                */
/*************************************************************************/
void US2066::locate( int x, int y )
{
  int temp = x + (y * 20);

  if(temp >= 20) temp = (temp - 20) + 0x20;

  writeCommand( (unsigned char)temp | 0x80 );  //set ddram address
  dly_tsk(20);
}

/*************************************************************************/
/* set contrast         */
/*************************************************************************/
void US2066::contrast( unsigned char cnt )
{
  //コントラスト調整
  writeCommand( 0x2a );  //RE=1
  writeCommand( 0x79 );  //SD=1
  writeCommand( 0x81 );  //contrast set
  writeCommand( cnt );  //contrast max
  writeCommand( 0x78 );  //SD=0
  writeCommand( 0x28 );  //set character size is normal.
  dly_tsk(100);
}

/*************************************************************************/
/* write strings                                                         */
/*************************************************************************/
int US2066::writeString( const char *str )
{
  unsigned char dat[1 * SO2002A_COLUMN + 1];
  int len = strlen(str);

  dat[0] = 0x40;
  len = (len > sizeof(dat) - 1) ? sizeof(dat) - 1 : len;
  memcpy( &dat[1], str, len );

  return blkWrite( i2cAddress, dat, len + 1 );
}

/*************************************************************************/
/* write strings                                                         */
/*************************************************************************/
int US2066::writeString( const char *str, unsigned int len )
{
  unsigned char dat[1 * SO2002A_COLUMN + 1];

  dat[0] = 0x40;
  len = (len > sizeof(dat) - 1) ? sizeof(dat) - 1 : len;
  memcpy( &dat[1], str, len );

  return blkWrite( i2cAddress, dat, len + 1 );
}

/*************************************************************************/
/* write strings                                                         */
/*************************************************************************/
int US2066::writeString( String str )
{
  return writeString( (const char *)&str[0], str.length() );
}

/*********************************************************************************/
/* end of file                                                                   */
/*********************************************************************************/

US2066.h ※<とか>などhtmlに変換した時に正しく変換されていない可能性が有るので、使わない事。
/****************************************************************************/
/* ssd1305  header                                                          */
/*                         Copyright (C) 2014 hamayan All Rights Reserved.  */
/****************************************************************************/
#ifndef US2066_h
#define US2066_h

#include <wire.h>

extern "C" {
}

//#define  US2066_0_ADR         0x3C
#define  SO2002A_LINES        2
#define  SO2002A_COLUMN       16
#define  SO2002A_DISPLAY_ON   0x04
#define  SO2002A_DISPLAY_OFF  0x00
#define  SO2002A_CURSOR_ON    0x02
#define  SO2002A_CURSOR_OFF   0x00
#define  SO2002A_BLINK_ON     0x01
#define  SO2002A_BLINK_OFF    0x00

class US2066 {
private:
  unsigned char i2cAddress;

  int blkWrite(unsigned char addr, const unsigned char *dat, unsigned int len);
  int writeCommand(unsigned char t_command);
  int writeData(unsigned char t_data);

public:
  US2066();
  void init( unsigned char adr );
  void clear( void );
  void OnOff( unsigned char onoff );
  void locate( int x, int y );
  void contrast( unsigned char cnt );
  int  writeString( const char *str );
  int  writeString( const char *str, unsigned int len );
  int  writeString( String str );
};

#endif  /*US2066_H*/
/****************************************************************************/
/*                         Copyright (C) 2014 hamayan All Rights Reserved.  */
/****************************************************************************/


さてこれを移植するのですが、まずC++の記述スタイルはCには適用できない事が多い!
例えば関数のオーバーライド
  int  writeString( const char *str );
  int  writeString( const char *str, unsigned int len );
  int  writeString( String str );

なんてもろにダメですね!

  Wire.endTransmission();

こう言った省略もダメです。
まぁ実際にコンパイル掛けてみると色々エラーや警告出ますんで、一つ一つ潰していくしかない。

クラスのメッソッドっぽく記述し直す必要があります。例えば
US2066 oled;
 oled.init( 10 );

みたいに書きたいとすれば、関数名のリストを作った構造体を用意して、それで呼び出す事になります。

結局以下の様になりました。
US2066.c ※<とか>などhtmlに変換した時に正しく変換されていない可能性が有るので、使わない事。
/*********************************************************************************/
/* US2066を使用したOLED SO1602AWGBの初期化と表示                                 */
/*                                         designed by hamayan since 2015/04/21  */
/*********************************************************************************/
#include  <US2066.h>

#if !defined( _MULTITASK_H_ )
#define  dly_tsk(tim)  delay(tim)
#define  rot_rdq()
#define  loc_cpu()     interrupts()
#define  unl_cpu()     noInterrupts()
#endif /*_MULTITASK_H_ */

static unsigned char i2cAddress;

static int blkWrite(unsigned char addr, const unsigned char *dat, unsigned int len);
static int writeCommand(unsigned char t_command);
static int writeData(unsigned char t_data);

/****************************************************************************/
/* I2C block Write                                                          */
/****************************************************************************/
static int blkWrite(unsigned char addr, const unsigned char *dat, unsigned int len)
{
  Wire.beginTransmission(addr);
  Wire.write(dat,len);
  return Wire.endTransmission( true );
}

/*************************************************************************/
/* write command         */
/*************************************************************************/
static int writeCommand(unsigned char t_command)
{
  unsigned char cmd[2];

  cmd[0] = 0x00;
  cmd[1] = t_command;

  return blkWrite( i2cAddress, cmd, sizeof(cmd) );
}

/*************************************************************************/
/* write data                                                            */
/*************************************************************************/
static int writeData(unsigned char t_data)
{
  unsigned char dat[2];

  dat[0] = 0x40;
  dat[1] = t_data;

  return blkWrite( i2cAddress, dat, sizeof(dat) );
}

/*************************************************************************/
/* US2066初期化                                                          */
/*************************************************************************/
static void init( unsigned char adr )
{
  i2cAddress = adr;  /*I2C address set*/

  dly_tsk(100);
  writeCommand( 0x01 );  //clear display
  dly_tsk(20);
  writeCommand( 0x02 );  //return home
  dly_tsk(2);
  writeCommand( 0x0f );  //send display on command
  dly_tsk(2);
  writeCommand( 0x01 );  //clear display
  dly_tsk(20);
}

/*************************************************************************/
/* clear display                                                         */
/*************************************************************************/
static void clear( void )
{
  dly_tsk(100);
  writeCommand( 0x01 );  //clear display
  dly_tsk(20);
}

/*************************************************************************/
/* display on/off                                                        */
/*************************************************************************/
static void OnOff( unsigned char onoff )
{
  writeCommand( onoff | (unsigned char)0x08 );  //display on/off,cursor on/off,blink on/off
  dly_tsk(20);
}

/*************************************************************************/
/* locate                                                                */
/*************************************************************************/
static void locate( int x, int y )
{
  int temp = x + (y * 20);

  if(temp >= 20) temp = (temp - 20) + 0x20;

  writeCommand( (unsigned char)temp | (unsigned char)0x80 );  //set ddram address
  dly_tsk(20);
}

/*************************************************************************/
/* set contrast         */
/*************************************************************************/
static void contrast( unsigned char cnt )
{
  //コントラスト調整
  writeCommand( 0x2a );  //RE=1
  writeCommand( 0x79 );  //SD=1
  writeCommand( 0x81 );  //contrast set
  writeCommand( cnt );  //contrast max
  writeCommand( 0x78 );  //SD=0
  writeCommand( 0x28 );  //set character size is normal.
  dly_tsk(100);
}

/*************************************************************************/
/* write strings                                                         */
/*************************************************************************/
static int writeString( const char *str )
{
  unsigned char dat[1 * SO2002A_COLUMN + 1];
  int len = strlen(str);

  dat[0] = 0x40;
  len = (len > sizeof(dat) - 1) ? sizeof(dat) - 1 : len;
  memcpy( &dat[1], str, len );

  return blkWrite( i2cAddress, dat, len + 1 );
}

/*************************************************************************/
/* メンバー関数のリスト                                                  */
/*************************************************************************/
const t_US2066_I2C oled =
{
  init,
  clear,
  OnOff,
  locate,
  contrast,
  writeString,
};

/*********************************************************************************/
/* end of file                                                                   */
/*********************************************************************************/

US2066.h ※<とか>などhtmlに変換した時に正しく変換されていない可能性が有るので、使わない事。
/****************************************************************************/
/* ssd1305  header                                                          */
/*                         Copyright (C) 2014 hamayan All Rights Reserved.  */
/****************************************************************************/
#ifndef US2066_h
#define US2066_h

#include <Wire.h>

//#define  US2066_0_ADR         0x3C
#define  SO2002A_LINES        2
#define  SO2002A_COLUMN       16
#define  SO2002A_DISPLAY_ON   0x04
#define  SO2002A_DISPLAY_OFF  0x00
#define  SO2002A_CURSOR_ON    0x02
#define  SO2002A_CURSOR_OFF   0x00
#define  SO2002A_BLINK_ON     0x01
#define  SO2002A_BLINK_OFF    0x00

#if 0
class US2066 {
private:
  unsigned char i2cAddress;

  int blkWrite(unsigned char addr, const unsigned char *dat, unsigned int len);
  int writeCommand(unsigned char t_command);
  int writeData(unsigned char t_data);

public:
  US2066();
  void init( unsigned char adr );
  void clear( void );
  void OnOff( unsigned char onoff );
  void locate( int x, int y );
  void contrast( unsigned char cnt );
  int  writeString( const char *str );
  int  writeString( const char *str, unsigned int len );
  int  writeString( String str );
};
#else
typedef struct
{
  void (*init)( unsigned char adr );
  void (*clear)( void );
  void (*OnOff)( unsigned char onoff );
  void (*locate)( int x, int y );
  void (*contrast)( unsigned char cnt );
  int  (*writeString)( const char *str );
} t_US2066_I2C;

extern const t_US2066_I2C oled;
#endif

#endif  /*US2066_H*/

/****************************************************************************/
/*                         Copyright (C) 2014 hamayan All Rights Reserved.  */
/****************************************************************************/

※関数のオーバーライドの代替関数はめんどうくさいので止めちゃいました!
※BME280の移植をしていて気付いたのですが、long long型が使えない、、、

上記ソースを、Lazurite IDEが入っているフォルダーの中のlibraries以下に、ソースと同じ名前にしたフォルダーを生成し、そこに収納します。
lazuriteImage_022.png

この状態でIDEを起動するとこのライブラリが左端のライブラリリストに表示されますので、チェックします。
※I2CなのでWireにもチェックを入れます。
lazuriteImage_023.png


で、冒頭の表示プログラムが以下になります。
blue_led.c ※<とか>などhtmlに変換した時に正しく変換されていない可能性が有るので、使わない事。
#include "blue_led_ide.h"		// Additional Header
#include  "mcu.h"

#define  BLUE_LED		26
#define  US2066_ADDRESS (0x3C << 0)

void setup(void)
{
  digitalWrite(BLUE_LED,HIGH);
  pinMode(BLUE_LED,OUTPUT);

  Wire.begin();
  I21MD=0;  /*100khz setup*/

  oled.init( US2066_ADDRESS );
  oled.contrast( 0xff );
  oled.clear();
  oled.OnOff( SO2002A_DISPLAY_ON | SO2002A_CURSOR_OFF | SO2002A_BLINK_OFF );
  oled.writeString( "Lazurite 920J" );
  oled.locate( 0, 1 );
  oled.writeString( "  with OLED" );
}

void loop(void)
{
  digitalWrite(BLUE_LED,HIGH);
  delay(1000);
  digitalWrite(BLUE_LED,LOW);
  delay(1000);
}

冒頭でmcu.hをインクルードしていますが、I2Cの速度を落とす為に必要です。
またsetupの先頭の
  Wire.begin();
  I21MD=0;  /*100khz setup*/

も必要です。

※まぁこれくらいのコード量なら移植はそれほどでもですが、もっと複雑なコードだと厳しいですね。BME280の移植はそれなりに手間でしたよ。

※IDEのライブラリにBME280は登録されていますが、、、SPIで動かした時のライブラリで、I2Cではありませんでしたorz。

※いや、最大の問題はこんなライブラリの移植ではなく、フォーラムのレスポンスの悪さだったりして。


Lazurite 920Jを立ち上げてみる 其の6 #LAZURITE920J #ラピスセミコンダクタ [Lazurite]

lazuriteImage_003.jpg

外部から低消費電力状態を解除したい!

sleep関数は時間が来ると低消費電力状態から解除されますが、それ以外に外部からこの低消費電力状態を解除したい時も多いかと思います。

この様な場合、wait_event関数を使う様です。
以下にサンプルを上げておきます。
Arduino同様外部割り込み端子として2番と3番が使用できますが、今回は2番に押しボタンスイッチを接続しています。
#define BLUE_LED       26
#define RED_LED        20
#define YELLO_LED      25

bool eventFlag = false;

void pin2Int( void )
{
  eventFlag = true;
}

void setup(void)
{
  pinMode( BLUE_LED, OUTPUT );
  pinMode( 2, INPUT_PULLUP );
  attachInterrupt( 0, pin2Int, FALLING );
}

void loop(void)
{
  digitalWrite(BLUE_LED, LOW);
  delay( 500 );
  digitalWrite(BLUE_LED, HIGH);
  eventFlag = false;
  wait_event( &eventFlag );
}

端子割り込みの中でbool型のフラグをtrueにしているだけの簡単なプログラムですね。

※低消費電力状態に入るとPower LEDは消灯されるが、青LEDは直前の端子の状態を維持している模様。

※では時間と外部割り込みの併用はできるのか?
先ほどのコードの wait_event( &eventFlag ); を sleep( 10 * 1000UL ); に変更してみましたが、外部割り込みでは起きない様です。うーん、、、一応sleepのマニュアルでは外部割り込みは有効と書いてあるので、低消費電力状態の解除方法が提供されていれば良いのですけれどね。


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