STM32L010F4P6マイコンを使ってI2C低電圧キャラクタ液晶モジュール(SB1602B)を動かしてみた

秋月電子通商で買ったSTM32L010F4P6を使ってみる。

前回のSTM32G031J6M6マイコンと一緒に 32ビットマイコンが今なら95円。
ということで STM32マイコン STM32L010F4P6 を買ってみた。

これで ストロベリーリナックス I2C低電圧キャラクタ液晶モジュール(16x2行) を動かしてみる。

ピンヘッダをつける

細ピンヘッダとDIP変換基板をはんだ付けする。

image01

データシートを確認する

この辺りは前回と同じなので省略。

STM32とLCDを接続

stm32l0_ds_p29

STM32L010F4P6の

  • pin 1 (BOOT0) --- GND
  • pin 4 (NRST) を I2CLCD のリセットピン(#1)と接続
  • pin 5 (VDDA) --- VDD(3V3)
  • pin 10 (PB9) --- 赤色LED(Vf=2V) --- 抵抗R(3k) --- VDD(3V3)
  • pin 15 (VSS) --- GND
  • pin 16 (VDD) --- VDD(3V3)
  • pin 17 (I2C1_SDA) を I2CLCD のSDAピン(#3)と接続
  • pin 18 (I2C1_SCL) を I2CLCD のSCLピン(#2)と接続

pin 4 (NRST) は GNDとの間にリセット用タクトスイッチを入れて, 抵抗R(3.9k)でプルアップしておく。
pin 17, 18 (SCL, SDA) は抵抗R(3k)でプルアップしておく。
抵抗値に深い意味はない(そこにあったので)。

I2C低電圧キャラクタ液晶モジュール(16x2行)の

  • pin 1 (~RST) --- STM32L010F4P6 pin#4
  • pin 2 (SCL) --- STM32L010F4P6 pin#18
  • pin 3 (SDA) --- STM32L010F4P6 pin#17
  • pin 4 (VSS) --- GND
  • pin 5 (VDD) --- VDD(3V3)

ブレッドボードで配線する

ニッケル水素電池(1.2V)を4直列から3端子レギュレータNJU7223F33で3.3V電源を作る。

LCDの下はこうで image02

これでOK image03

まだ何も起きない。(あたりまえ)
STM32マイコンにプログラムを書き込まないと。

STM32CubeIDEでプロジェクトを新規作成

File -> New でSTM32 プロジェクトを選択して,
MCU: STM32L010F4を選んで新規作成する。 capture01

クロックはHSI RC発振 (16MHz)を4分周して生成した4MHzをSYSCLKにしておきます。 capture02

  • PA4をGPIO_Output
  • I2C1を400kHzで駆動(もちろん100kHzでもいい)

capture03

この設定でCubeIDEに生成してもらったmain.cの USER CODE BEGIN ~ END の間をいじる。(それ以外に書いたものは消されるよ)

このままでは前回と同じになるのでC++プロジェクトにします。

なんと, C++14が使えるのを発見したので。

Core/Src/main.c

main.cppがあってもCubeIDEのコード生成が無視するので, エントリポイントはC言語にしておく。

Core/Src/main.c
/* USER CODE BEGIN Header */
/**
 ******************************************************************************
 * @file           : main.c
 * @brief          : Main program body
 ******************************************************************************
 * @attention
 *
 * <h2><center>&copy; Copyright (c) 2021 STMicroelectronics.
 * All rights reserved.</center></h2>
 *
 * This software component is licensed by ST under BSD 3-Clause license,
 * the "License"; You may not use this file except in compliance with the
 * License. You may obtain a copy of the License at:
 *                        opensource.org/licenses/BSD-3-Clause
 *
 ******************************************************************************
 */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/
I2C_HandleTypeDef hi2c1;

/* USER CODE BEGIN PV */
/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_I2C1_Init(void);
/* USER CODE BEGIN PFP */

extern void application_setup();
extern void application_loop();

/* USER CODE END PFP */

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

/* USER CODE END 0 */

/**
 * @brief  The application entry point.
 * @retval int
 */
int main(void) {
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick.
   */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_I2C1_Init();
  /* USER CODE BEGIN 2 */
  application_setup();
  /* USER CODE END 2 */

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

    /* USER CODE BEGIN 3 */
    application_loop();
  }
  /* USER CODE END 3 */
}

/**
 * @brief System Clock Configuration
 * @retval None
 */
void SystemClock_Config(void) {
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
  RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};

  /** Configure the main internal regulator output voltage
   */
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
  /** Initializes the RCC Oscillators according to the specified parameters
   * in the RCC_OscInitTypeDef structure.
   */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_DIV4;
  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) {
    Error_Handler();
  }
  /** Initializes the CPU, AHB and APB buses clocks
   */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK |
                                RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK) {
    Error_Handler();
  }
  PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_I2C1;
  PeriphClkInit.I2c1ClockSelection = RCC_I2C1CLKSOURCE_PCLK1;
  if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK) {
    Error_Handler();
  }
}

/**
 * @brief I2C1 Initialization Function
 * @param None
 * @retval None
 */
static void MX_I2C1_Init(void) {

  /* USER CODE BEGIN I2C1_Init 0 */

  /* USER CODE END I2C1_Init 0 */

  /* USER CODE BEGIN I2C1_Init 1 */

  /* USER CODE END I2C1_Init 1 */
  hi2c1.Instance = I2C1;
  hi2c1.Init.Timing = 0x00000004;
  hi2c1.Init.OwnAddress1 = 0;
  hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
  hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
  hi2c1.Init.OwnAddress2 = 0;
  hi2c1.Init.OwnAddress2Masks = I2C_OA2_NOMASK;
  hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
  hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
  if (HAL_I2C_Init(&hi2c1) != HAL_OK) {
    Error_Handler();
  }
  /** Configure Analogue filter
   */
  if (HAL_I2CEx_ConfigAnalogFilter(&hi2c1, I2C_ANALOGFILTER_ENABLE) != HAL_OK) {
    Error_Handler();
  }
  /** Configure Digital filter
   */
  if (HAL_I2CEx_ConfigDigitalFilter(&hi2c1, 0) != HAL_OK) {
    Error_Handler();
  }
  /* USER CODE BEGIN I2C1_Init 2 */

  /* USER CODE END I2C1_Init 2 */
}

/**
 * @brief GPIO Initialization Function
 * @param None
 * @retval None
 */
static void MX_GPIO_Init(void) {
  GPIO_InitTypeDef GPIO_InitStruct = {0};

  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOA_CLK_ENABLE();

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);

  /*Configure GPIO pin : PA4 */
  GPIO_InitStruct.Pin = GPIO_PIN_4;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}

/* USER CODE BEGIN 4 */

/* USER CODE END 4 */

/**
 * @brief  This function is executed in case of error occurrence.
 * @retval None
 */
void Error_Handler(void) {
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */
  __disable_irq();
  while (1) {
  }
  /* USER CODE END Error_Handler_Debug */
}

#ifdef USE_FULL_ASSERT
/**
 * @brief  Reports the name of the source file and the source line number
 *         where the assert_param error has occurred.
 * @param  file: pointer to the source file name
 * @param  line: assert_param error line source number
 * @retval None
 */
void assert_failed(uint8_t *file, uint32_t line) {
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line
     number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

Core/Src/Application.cpp

C++言語側のエントリポイント。

.cファイルはCコンパイラがコンパイルして作るオブジェクトコード(.o)で
.cppファイルはC++コンパイラがコンパイルして作るオブジェクトコード(.o)で
Cリンケージがどうのこうのとかのリンクエラーがでるのでこのファイルを間に挟むとする。
他にいい方法がわからない。

Core/Src/Application.cpp
/*
 * Application.cpp
 *
 * Copyright 2021 Akihiro Yamamoto.
 * Licensed under the Apache License, Version 2.0
 * <https://spdx.org/licenses/Apache-2.0.html>
 *
 */
#include <ST7032iLcd.hpp>

extern I2C_HandleTypeDef hi2c1;

static ST7032iLcd i2c_lcd(hi2c1);

extern "C" void application_setup() {
  static const char *lines[] = {u8"Strawberry Linux", u8"I2C エキショウ モジュール"};
  i2c_lcd.init();
  i2c_lcd.puts(lines[0]);
  i2c_lcd.setDdramAddress(0x40);
  i2c_lcd.putString(lines[1]);
}

extern "C" void application_loop() {
  static ST7032iLcd::IconCode i = 0;

  i2c_lcd.showIcon(0x1fff ^ (1 << i));
  i = (i + 1) % 13;

  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);
  HAL_Delay(200);
  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);
  HAL_Delay(200);
}

Core/Inc/ST7032iLcd.hpp

前回のCソースファイルをC++にしてみた。

Core/Inc/ST7032iLcd.hpp
/*
 * ST7032iLcd.hpp
 *
 * Copyright 2021 Akihiro Yamamoto.
 * Licensed under the Apache License, Version 2.0
 * <https://spdx.org/licenses/Apache-2.0.html>
 *
 */

#ifndef INC_ST7032ILCD_HPP_
#define INC_ST7032ILCD_HPP_
#include "main.h"

#include <array>
#include <cstdint>
#include <cstring>
#include <string>
#include <vector>

class ST7032iLcd {
public:
  //
  ST7032iLcd(I2C_HandleTypeDef &h, uint8_t addr = 0x3e)
      : i2c(h), i2c_address(addr) {}
  //
  bool init(uint8_t contrast = 0b101000);
  void setContrast(uint8_t contrast);
  //
  template <std::size_t N>
  void sendCommands(const std::array<uint8_t, N> &cmds) {
    master_transmit(i2c, i2c_address, I2C_LCD_CBYTE_COMMAND, N, cmds.data());
  }
  void sendCommands(const std::vector<uint8_t> &cmds) {
    master_transmit(i2c, i2c_address, I2C_LCD_CBYTE_COMMAND, cmds.size(),
                    cmds.data());
  }
  void sendCommand(uint8_t cmd) {
    master_transmit(i2c, i2c_address, I2C_LCD_CBYTE_COMMAND, 1, &cmd);
  }
  //
  template <std::size_t N> void sendData(const std::array<uint8_t, N> &data) {
    master_transmit(i2c, i2c_address, I2C_LCD_CBYTE_DATA, N, data.data());
  }
  void sendData(const std::vector<uint8_t> &data) {
    master_transmit(i2c, i2c_address, I2C_LCD_CBYTE_DATA, data.size(),
                    data.data());
  }
  void sendDatum(uint8_t datum) {
    master_transmit(i2c, i2c_address, I2C_LCD_CBYTE_DATA, 1, &datum);
  }
  //
  void puts(const char *s) {
    master_transmit(i2c, i2c_address, I2C_LCD_CBYTE_DATA, std::strlen(s),
                    reinterpret_cast<const uint8_t *>(s));
  }
  void putString(const std::string &s);
  //
  using Command = uint8_t;
  const static constexpr Command CmdClearDisplay = 0b00000001;
  const static constexpr Command CmdReturnHome = 0b00000010;
  //
  void setDdramAddress(uint8_t addr) { sendCommand(0x80 | (addr & 0x7f)); }
  //
  using IconCode = uint16_t;
  const static constexpr IconCode IconA = 1 << 12;
  const static constexpr IconCode IconB = 1 << 11;
  const static constexpr IconCode IconC = 1 << 10;
  const static constexpr IconCode IconD = 1 << 9;
  const static constexpr IconCode IconE = 1 << 8;
  const static constexpr IconCode IconF = 1 << 7;
  const static constexpr IconCode IconG = 1 << 6;
  const static constexpr IconCode IconH = 1 << 5;
  const static constexpr IconCode IconI = 1 << 4;
  const static constexpr IconCode IconJ = 1 << 3;
  const static constexpr IconCode IconK = 1 << 2;
  const static constexpr IconCode IconL = 1 << 1;
  const static constexpr IconCode IconM = 1 << 0;
  //
  void showIcon(IconCode bitflag);

private:
  I2C_HandleTypeDef &i2c;
  const uint8_t i2c_address;
  //
  const static constexpr uint8_t LCD_TIMEOUT = 100;
  const static constexpr uint8_t LCD_NUM_OF_ROW_CHARACTERS = 16;
  //
  using CommByte = uint8_t;
  const static constexpr CommByte I2C_LCD_CBYTE_COMMAND = 0x00;
  const static constexpr CommByte I2C_LCD_CBYTE_DATA = 0x40;
  const static constexpr CommByte I2C_LCD_CBYTE_CONTINUATION = 0x80;
  //
  static void master_transmit(I2C_HandleTypeDef &i2c, uint8_t i2c_address,
                              CommByte cbyte, size_t size, const uint8_t *data);
};

#endif /* INC_ST7032ILCD_H_ */

Core/Src/ST7032iLcd.cpp

現代のプログラムはコード効率の悪さを気にせずにutf8を使うもんだろ。

ということでutf-8 -> shift-jis半角カタカナ変換を入れてみた。
utf-8の3バイトエンコード部分
https://orange-factory.com/sample/utf8/code3/ef.html#HalfwidthandFullwidthForms
に入っている半角カナをST7032の半角カナにマッピングする。
これは元々HD44780に入っていた半角カナらしいね。

具体的にU+FF61~U+FF9Fを0b10100001~0b11011111にマッピングする。
ツライ。

st7032_ds_p62

Core/Src/ST7032iLcd.cpp
/*
 * ST7032iLcd.cpp
 *
 * Copyright 2021 Akihiro Yamamoto.
 * Licensed under the Apache License, Version 2.0
 * <https://spdx.org/licenses/Apache-2.0.html>
 *
 */
#include <ST7032iLcd.hpp>

// clang-format off
inline void i2c_lcd_wait_a_moment() {
    asm("NOP");asm("NOP");asm("NOP");asm("NOP");asm("NOP");
    asm("NOP");asm("NOP");asm("NOP");asm("NOP");asm("NOP");
    // 10
    asm("NOP");asm("NOP");asm("NOP");asm("NOP");asm("NOP");
    asm("NOP");asm("NOP");asm("NOP");asm("NOP");asm("NOP");
    // 20
}
// clang-format on

bool ST7032iLcd::init(uint8_t contrast) {
  sendCommands({
      0b00111000, // function set
      0b00111001, // function set
      0b00010100, // interval osc
      0b01101100, // follower control
  });
  setContrast(contrast);
  HAL_Delay(200);

  // second step
  sendCommands({
      0b00111000, // function set
      0b00001100, // Display On
      0b00000001, // Clear Display
  });
  HAL_Delay(2);

  return true;
}

void ST7032iLcd::setContrast(uint8_t contrast) {
  uint8_t lo = contrast & 0xf;
  uint8_t hi = (contrast >> 4) & 0x3;
  sendCommands({
      static_cast<uint8_t>(0b01110000 | lo), // contrast Low
      static_cast<uint8_t>(0b01011100 | hi), // contast High/icon/power
  });
}

inline bool Top4bitHigh(uint8_t x) { return (x & 0b11111000) == 0b11110000; }
inline bool Top3bitHigh(uint8_t x) { return (x & 0b11110000) == 0b11100000; }
inline bool Top2bitHigh(uint8_t x) { return (x & 0b11100000) == 0b11000000; }
constexpr static const uint16_t CodePointHankakuKatakanaBegin = 0xff61;
constexpr static const uint16_t CodePointHankakuKatakanaEnd = 0xff9f;
inline bool isHankakuKatakana(uint16_t x) {
  return (CodePointHankakuKatakanaBegin <= x &&
          x <= CodePointHankakuKatakanaEnd);
}

// utf-8 to ascii & sjis kana
void ST7032iLcd::putString(const std::string &s) {
  uint8_t buff[LCD_NUM_OF_ROW_CHARACTERS];
  std::size_t buff_idx = 0;

  for (std::size_t idx = 0;
       buff_idx < LCD_NUM_OF_ROW_CHARACTERS && idx < s.size();) {
    if (Top4bitHigh(s[idx])) {
      // utf8 4-byte encoded character
      // map to '?'
      buff[buff_idx++] = '?';
      idx += 4;
    } else if (Top3bitHigh(s[idx])) {
      // utf8 3-byte encoded character
      uint8_t top4bit = s[idx + 0] & 0x0f;
      uint8_t mid6bit = s[idx + 1] & 0x3f;
      uint8_t low6bit = s[idx + 2] & 0x3f;
      uint16_t cp = (top4bit << 12) | (mid6bit << 6) | (low6bit << 0);
      if (isHankakuKatakana(cp)) {
        // Hankaku katakana
        buff[buff_idx++] = 0b10100001 + (cp - CodePointHankakuKatakanaBegin);
      } else {
        // map to '?'
        buff[buff_idx++] = '?';
      }
      idx += 3;
    } else if (Top2bitHigh(s[idx])) {
      // utf8 2-byte encoded character
      // map to '?'
      buff[buff_idx++] = '?';
      idx += 2;
    } else {
      // utf8 1-byte encoded character
      buff[buff_idx++] = s[idx];
      idx += 1;
    }
  }
  master_transmit(i2c, i2c_address, I2C_LCD_CBYTE_DATA, buff_idx, buff);
}

struct Icon {
  ST7032iLcd::IconCode icon_code;
  uint8_t addr;
  uint8_t bit;
};

static const Icon I2C_LCD_ICON_DATA[13] = {
    {ST7032iLcd::IconA, 0x00, 0b10000}, // S1  ANTENNA
    {ST7032iLcd::IconB, 0x02, 0b10000}, // S11 TEL
    {ST7032iLcd::IconC, 0x04, 0b10000}, // S21
    {ST7032iLcd::IconD, 0x06, 0b10000}, // S31

    {ST7032iLcd::IconE, 0x07, 0b10000}, // S36 UP ARROW
    {ST7032iLcd::IconF, 0x07, 0b01000}, // S37 DOWN ARROW

    {ST7032iLcd::IconG, 0x09, 0b10000}, // S46 LOCKED
    {ST7032iLcd::IconH, 0x0b, 0b10000}, // S56

    {ST7032iLcd::IconI, 0x0d, 0b10000}, // S66 BATTERY LOW
    {ST7032iLcd::IconJ, 0x0d, 0b01000}, // S67 BATTERY MID
    {ST7032iLcd::IconK, 0x0d, 0b00100}, // S68 BATTERY HIGH
    {ST7032iLcd::IconL, 0x0d, 0b00010}, // S69 BATTERY FRAME

    {ST7032iLcd::IconM, 0x0f, 0b10000}, // S76
};

void ST7032iLcd::showIcon(IconCode bitflag) {
  std::array<uint8_t, 16> buff{0};

  for (const Icon &i : I2C_LCD_ICON_DATA) {
    if (bitflag & i.icon_code) {
      buff[i.addr] |= i.bit;
    }
  }
  for (uint8_t i = 0; i < buff.size(); ++i) {
    sendCommands({
        0b00111001,                           // function set
        static_cast<uint8_t>(0b01000000 | i), // set icon address
    });
    sendDatum(buff[i]);
  }
}

void ST7032iLcd::master_transmit(I2C_HandleTypeDef &i2c, uint8_t i2c_address,
                                 CommByte cbyte, size_t size,
                                 const uint8_t *data) {
  if (1 <= size) {
    size_t i;
    std::vector<uint8_t> buff(size * 2);

    for (i = 0; i < (size - 1); ++i) {
      buff[i * 2 + 0] = I2C_LCD_CBYTE_CONTINUATION | cbyte;
      buff[i * 2 + 1] = data[i];
    }
    buff[i * 2 + 0] = cbyte;
    buff[i * 2 + 1] = data[i];
    HAL_I2C_Master_Transmit(&i2c, i2c_address << 1, buff.data(), buff.size(),
                            LCD_TIMEOUT);
    i2c_lcd_wait_a_moment();
  }
}

プロジェクトのビルド

Ctrl + B でビルド。

capture04

22:39:22 **** Incremental Build of configuration Debug for project hello_stm32l0 ****
make -j16 all 
arm-none-eabi-size   hello_stm32l0.elf 
   text	   data	    bss	    dec	    hex	filename
  15364	    132	   1688	  17184	   4320	hello_stm32l0.elf
Finished building: default.size.stdout
 

22:39:22 Build Finished. 0 errors, 0 warnings. (took 165ms)

あああ。真っ赤じゃないですか。 capture05

このプログラムはSTM32L010F4P6に搭載されている RAM 2キロバイトのうち 1.77キロバイトを, さらに FLASHメモリ 16キロバイトのうち 15.13キロバイトを使う。
これだけでぱっつんぱっつんになってしまった。
やっぱりC++言語はフットプリントが増えるな。

でも今回はこれしかしないので問題ない。

Nucleoボード付属のST-Link/V2.1でプログラミング

NucleoボードについてるST-Link/V2.1を使います。

stm32l0_ds_p31

こちらはSTM32L010F4P6のピン

stm32l0_ds_p31

NucleoボードのCN2ジャンパーを外して
STM32L010F4P6の

  • pin 4 (NRST) を ST-Link のRSTピン(#5)と接続
  • pin 15 (VSS) を ST-Link のGNDピン(#3)と接続
  • pin 19 (SWDIO) を ST-Link のSWDIOピン(#4)と接続
  • pin 20 (SWCLK) を ST-Link のSWCLKピン(#2)と接続

image04

実行にはプログラマーは不要。 coverimage

GitHubリポジトリ

https://github.com/ak1211/hello_stm32l0/tree/FirstRelease

https://github.com/ak1211/hello_stm32l0/releases/tag/FirstRelease