製作モジュール一覧

2019年4月8日月曜日

STM32: I2C接続のLCD:AQM1602を使う(Nucleo-F446RE)

秋月のI2C接続のキャラクタLCDのAQM1602を動作させました。

I2Cについては以下の記事を参考にしました。


プロジェクト
https://github.com/ryood/STM32Cube_Test/tree/master/SW4STM32/Nucleo-F446_I2C_AQM1602_Test1

実行環境

  • Nucleo-F446RE
  • STM32CubeMX Version 5.1.0
  • System Workbench for STM32 - C/C++ Embedded Development Tools for MCU Version: 2.8.1.201903050911

配線

SCLとSDAは4.7kΩでPullUpしています。

STM32Cubeの設定


Connectivity
  I2C1
    Mode: I2C
  Prameter Settings
    Master Features
      I2C Speed Mode: Standard Mode
      I2C Clock Speed(Hz): 100000
   
Pinout ViewでPinを割り当て
  PB8: I2C1_SCL
  PB9: I2C1_SDA

SW4STM32でコードを追加(一部抜粋)


/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
#define AQM1602_ADDRESS (0x3e << 1)
/* USER CODE END PD */

AQM1602のI2Cアドレスを指定します。Arduinoは7bit右詰めですが、STM32Cubeは7bitで左詰めなので左シフトしています。

参考「I2C addressing on STM32F4-Discovery

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

// I2C LCD : Akizuki AQM1602

void lcd_cmd(uint8_t x)
{
  uint8_t aTxBuffer[2] = { 0x00, x };
  while (HAL_I2C_Master_Transmit(&hi2c1, (uint16_t)AQM1602_ADDRESS, (uint8_t*)aTxBuffer, 2, 1000) != HAL_OK) {
    if (HAL_I2C_GetError(&hi2c1) != HAL_I2C_ERROR_AF)
    {
      Error_Handler();
    }
  }
}

void lcd_data(uint8_t x)
{
  uint8_t aTxBuffer[2] = { 0x40, x };
  while (HAL_I2C_Master_Transmit(&hi2c1, (uint16_t)AQM1602_ADDRESS, (uint8_t*)aTxBuffer, 2, 1000) != HAL_OK) {
    if (HAL_I2C_GetError(&hi2c1) != HAL_I2C_ERROR_AF)
    {
      Error_Handler();
    }
  }
}

void lcd_puts(const char *s)
{
  while(*s) lcd_data(*s++);
}

// param:
//  contrast: 0 ~ 63 (最初は大きくして調整)
void lcd_init(uint8_t contrast)
{
  // LCD initialize
  lcd_cmd(0x38); // function set
  lcd_cmd(0x39); // function set
  lcd_cmd(0x14); // interval osc
  lcd_cmd(0x70 | (contrast & 15)); // contrast low
  lcd_cmd(0x5c | (contrast >> 4 & 3)); // contrast high / icon / power
  lcd_cmd(0x6c); // follower control
  HAL_Delay(300);
  lcd_cmd(0x38); // function set
  lcd_cmd(0x0c); // display on
  lcd_cmd(0x01); // clear display
  HAL_Delay(2);
}

void lcd_move(uint8_t pos){
  lcd_cmd(0x80 | pos);
}

void lcd_pos(uint8_t raw, uint8_t col) {
  lcd_cmd(0x80 | ((raw & 0x01) << 6) | col);
}

void lcd_clear() {
  lcd_cmd(0x01);
}

/* USER CODE END 0 */

AQM1602の制御関数です。

  /* USER CODE BEGIN 2 */
  lcd_init(32);
  lcd_puts("Hello STM32");
  lcd_pos(1, 0);
  lcd_puts("AQM1602");
  /* USER CODE END 2 */

AQM1602を初期化。


  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  uint16_t cnt = 0;
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
    HAL_GPIO_TogglePin(LD2_GPIO_Port, LD2_Pin);
    char strBuffer[17] = {0};
    sprintf(strBuffer, "CNT=%05d", cnt);
    lcd_pos(1, 0);
    lcd_puts(strBuffer);
    cnt++;
    HAL_Delay(100);
  }
  /* USER CODE END 3 */

メインループではインクリメントした数値の表示とLチカを行っています。

I2C通信のようす

ch1:SDA ch2:SCL

2019年4月2日火曜日

STM32: 内蔵DACをDMA経由で使う(Nucleo-F446RE)

内蔵DACをDMA経由で使ってみました。データをあらかじめ用意できれば、DMAにデータ転送をまかせて、CPUは他の処理が行えます。

参考
「Elastic Notes」さんの「Usage DMA and DAC in STM32CubeMX

プロジェクト
https://github.com/ryood/STM32Cube_Test/tree/master/SW4STM32/Nucleo-F446_DAC_DMA_Test2

実行環境

  • Nucleo-F446RE
  • STM32CubeMX Version 5.1.0
  • System Workbench for STM32 - C/C++ Embedded Development Tools for MCU Version: 2.8.1.201903050911

4096サンプルのサイン波テーブルを作成して内蔵DACから出力します。

STM32CubeMXの設定


Clock Configuration
  PLL Source Mux: HSE
  HCLK: 180MHz

Pinout & Configuration
  Timers
    TIM6
      Mode: Activatedをチェック
      Counter Period: 220
      Trigger Event Selection: Update Event

180MHz駆動するとAPB1 Timer clocksは90MHzになります。4096サンプルで1波形のサイン波を出力するので、1kHzのサイン波を出力しようとすると
90MHz / prescaler / 4096 = 1kHz
なので
prescaler = 90MHz / (1kHz * 4096) ≒ 22.0
ですが、prescalerを22に設定するとDACから信号が出力されませんでした。100Hzにしようとprescalerを220に設定するとOKでした。

  Analog
    DAC
      Mode: OUT1 Configurationをチェック
      Prameter Settings
        Trigger: Timer 6 Trigger Out event
      NVIC Settings
        Enableをチェック
      DMA Settings
        DMA Request: DAC1を追加
        Mode: Circular
        Increment Address: Memory
        Data Width: Half Word
     

 SW4STM32でコードを追加(一部抜粋)


/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include <math.h>
/* USER CODE END Includes */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
#define SINE_TABLE_SIZE (4096)
/* USER CODE END PD */

/* USER CODE BEGIN PV */
uint16_t sine_wave_array[SINE_TABLE_SIZE];
/* USER CODE END PV */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
static void generateSineWave(void)
{
  for (int i = 0; i < SINE_TABLE_SIZE; i++) {
      float fv = ((float)i / SINE_TABLE_SIZE) * 2.0f - 1.0f;
      float phi = (float)M_PI * fv;
      sine_wave_array[i] = 4095 * ((sinf(phi) + 1.0f) / 2.0f);
  }
}
/* USER CODE END 0 */

  /* USER CODE BEGIN 2 */
  generateSineWave();
  HAL_TIM_Base_Start(&htim6);
  HAL_DAC_Start_DMA(&hdac, DAC_CHANNEL_1, (uint32_t*)sine_wave_array, SINE_TABLE_SIZE, DAC_ALIGN_12B_R);
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */

Memory→DACのデーター転送はTimer駆動(TIM6)のDMAにまかせているので、プログラム(while(1)ループ)では何もしていません。

出力波形

いつものように、サイン波形の最大振幅付近で若干クリップしています。

99.6Hzのサイン波になりました。水晶がクロック源なので少し誤差が大きいような・・・(@@?

Prescaler Prescler(丸め) 誤差
219.7265625 220 0.1244%

期待周期(ms) 実測周期(ms) 誤差
10 10.04 0.4000%

2019年3月30日土曜日

STM32: 内蔵DACを使う(Nucleo-F446RE)

Nucleo-F446REの内蔵DACからSIN波を出力しました。

参考
<STM32Cube>\Repository\STM32Cube_FW_F4_V1.24.0\Projects\STM32446E_EVAL\Examples\DAC\DAC_SimpleConversion

プロジェクト
https://github.com/ryood/STM32Cube_Test/tree/master/SW4STM32/Nucleo-F446_DAC_Test5

実行環境

  • Nucleo-F446RE
  • STM32CubeMX Version 5.1.0
  • System Workbench for STM32 - C/C++ Embedded Development Tools for MCU Version: 2.8.1.201903050911

STM32CubeMXの設定



STM32CubeMXに[Report]という機能があったので出力してみました。

https://github.com/ryood/STM32Cube_Test/blob/master/SW4STM32/Nucleo-F446_DAC_Test5/Nucleo-F446_DAC_Test5.pdf

SW4STM32でコードを追加(一部抜粋)

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include <math.h>
/* USER CODE END Includes */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  double phi = 0.0;
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
    uint16_t sinv = 4095 * ((sin(phi) + 1.0) / 2.0);
    if (HAL_DAC_SetValue(&hdac, DAC_CHANNEL_1, DAC_ALIGN_12B_R, sinv) != HAL_OK)
    {
      Error_Handler();
    }
    if (HAL_DAC_SetValue(&hdac, DAC_CHANNEL_2, DAC_ALIGN_12B_R, sinv) != HAL_OK)
    {
      Error_Handler();
    }
    phi += 0.01;
  }
  /* USER CODE END 3 */
}

位相角を0.01ずつ増やしてsinの値を求め、12bit値に変換して2chある内蔵DACから出力しています。

出力結果


ch1:DAC1(PA4) ch2:DAC2(PA5)

DAC2はNucleoボード上でLEDに接続されているため、上側がクリップしています。DAC1も上下の最大振幅付近で若干クリップしています。