Add mozc-dial nine dial edition.

Co-authored-by: Takashi Toyoshima <toyoshim@google.com>
Co-authored-by: Shun Ikejima <ikejima@google.com>
This commit is contained in:
Shun Ikejima
2025-10-28 18:19:10 +09:00
parent 1775d344f1
commit 994d22bb71
76 changed files with 810960 additions and 7327 deletions

View File

@@ -16,6 +16,10 @@ We have included pre-built firmware under `prebuilt/`, so you can use them as is
Use `main.uf2` and `sub.uf2` for the 9-dial edition, and `one_dial.uf2` for the 1-dial edition.
We have also prepared `main_no_pull.uf2`, `sub_no_pull.uf2`, and `one_dial_no_pull.uf2` that do not use internal pull-up for the sensors. For details, please see [About Sensor Adjustment](#about-sensor-adjustment).
If the dial rotation is reversed, try using the firmware with `backward` in its name. It seems that the direction of rotation may differ depending on the shipping time even for the same model number product.
## Guide to Developing Your Own Firmware
Install [Visual Studio Code](https://code.visualstudio.com/) and add the [Raspberry Pi Pico extension](https://marketplace.visualstudio.com/items?itemName=raspberry-pi.raspberry-pi-pico).

View File

@@ -8,7 +8,7 @@
- common/ : 各ボード共通で用いられるライブラリのソースファイル
- main/ : 9ダイヤル版メインチップ用のソースファイルとプロジェクト
- sub/ : 9ダイヤル版サブチップ用のソースファイルとプロジェクト
- one_dial/ : 1ダイヤル版 Raspberry Pi Pico用のソーファイルとプロジェクト
- one_dial/ : 1ダイヤル版 Raspberry Pi Pico用のソーファイルとプロジェクト
## 事前にビルドしたファームウェア
@@ -16,6 +16,10 @@
9ダイヤル板は`main.uf2``sub.uf2`を、1ダイヤル板は`one_dial.uf2`を使用します。
それぞれセンサに内部pull-upを使わない`main_no_pull.uf2``sub_no_pull.uf2``one_dial_no_pull.uf2`も用意しています。詳しくは[センサの調整について](#センサの調整について)をご覧ください。
ダイヤルの回転方向が逆だった場合には`backward`の名前がついたものを使用してみてください。同じ型番の製品でも出荷時期により回転方向が異なるようです。
## 独自のファームウェア開発の手引き
[Visual Studio Code](https://code.visualstudio.com/) をインストールし、[Raspberry Pi Pico拡張](https://marketplace.visualstudio.com/items?itemName=raspberry-pi.raspberry-pi-pico) を追加します。
@@ -52,9 +56,9 @@ Activity Barの`Raspberry Pi Pico Projects`の拡張機能から`Import Project`
などを定義し、`CMakeFiles.txt`のボード設定で指定する事で、キャッシュミス時のQSPI経由でのEEPROMアクセスを最適化し、さらなる性能を引き出す事も可能です。
### センサの調整について
### センサの調整について
標準ではセンサは内部抵抗でpull-upされています。外部抵抗によりpull-upで調整したい場合、`photo_sensor.cc``PhotoSensor::PhotoSensor()`内にある`gpio_pull_up(gpio);``gpio_disable_pulls(gpio);`に変更してください。
標準ではセンサは内部抵抗でpull-upされています。外部抵抗によりpull-upで調整したい場合、`photo_sensor.cc``PhotoSensor::PhotoSensor()`内にある`gpio_pull_up(gpio);``gpio_disable_pulls(gpio);`に変更してください。
あるいは、内部抵抗を有効にしたまま外部抵抗との合成抵抗でpull-upする事も可能です。この場合、内部抵抗は公称値で50-80KΩ、外部抵抗とは並列接続になります。

View File

@@ -49,9 +49,10 @@ bool MotorController::OnAlarm(repeating_timer* t) {
return true;
}
MotorController::MotorController(Mode mode) {
MotorController::MotorController(Mode mode, Direction direction)
: direction_(direction) {
if (mode == Mode::k9Motor) {
// Each decoder is responsible for a specific phase to driver 1 of 8 motor
// Each decoder is responsible for a specific phase to drive 1 of 8 motor
// drivers. As we have 4 phases, it can drive 4 motors at the same time, and
// by time division multiplexing, we make them drive 8 motors.
decoder_[0] = std::make_unique<Decoder>(1, 2, 3, 4);
@@ -88,7 +89,7 @@ void MotorController::Step() {
size_t start_index = (phase_ & 1) ? kNumOfPhases : 0;
size_t half_phase = phase_ >> 1;
for (size_t i = start_index; i < start_index + kNumOfPhases; ++i) {
if (!decoder_[i]) {
if (!decoder_[i % kNumOfPhases]) {
continue;
}
if (started_[i]) {
@@ -104,5 +105,9 @@ void MotorController::Step() {
gpio_put(19, on && half_phase == 2);
gpio_put(20, on && half_phase == 3);
phase_ = (phase_ + 7) % 8;
if (direction_ == Direction::kForward) {
phase_ = (phase_ + 1) % 8;
} else if (direction_ == Direction::kBackward) {
phase_ = (phase_ + 7) % 8;
}
}

View File

@@ -13,7 +13,8 @@
class MotorController final {
public:
enum class Mode { k1Motor, k9Motor };
explicit MotorController(Mode = Mode::k9Motor);
enum class Direction { kForward, kBackward };
explicit MotorController(Mode = Mode::k9Motor, Direction = Direction::kForward);
MotorController(const MotorController&) = delete;
MotorController& operator=(const MotorController&) = delete;
~MotorController();
@@ -33,6 +34,7 @@ class MotorController final {
bool started_[kNumOfMotors] = { false };
uint8_t phase_ = 0;
repeating_timer timer_;
Direction direction_ = Direction::kForward;
};
#endif // COMMON_MOTOR_CONTROLLER_H_

View File

@@ -6,6 +6,8 @@
#include "hardware/gpio.h"
//#define NO_SENSOR_PULL
PhotoSensor::PhotoSensor(int8_t bit0,
int8_t bit1,
int8_t bit2,
@@ -16,7 +18,13 @@ PhotoSensor::PhotoSensor(int8_t bit0,
for (int8_t gpio : bits) {
gpio_init(gpio);
gpio_set_dir(gpio, GPIO_IN);
gpio_pull_up(gpio); // Built-in 50-80K pull-up
#ifdef NO_SENSOR_PULL
gpio_disable_pulls(gpio);
#else
// Built-in 50-80K pull-up is expected, but the actual value appears to
// depend on the RP2040's shipping years?
gpio_pull_up(gpio);
#endif // NO_SENSOR_PULL
}
}

View File

@@ -41,8 +41,8 @@ const std::vector<uint8_t> a = {
0x14, // q
0x04, // a
0x1d, // z
0x39, // <CAPS>
0x2c, // <SPACE>
0x39, // <CAPS>
};
const std::vector<uint8_t> fn_a = {};
const std::vector<uint8_t> modifier_a = {};

View File

@@ -43,6 +43,8 @@ int main() {
PhotoSensor(24, 25, 26, 27), // I
};
const std::array<int8_t, 9> sensor_indices = { 0, 1, 2, 3, 4, 5, 6, -1, 7 };
std::array<DialController, 9> dials = {
DialController(), // A
DialController(), // B
@@ -98,37 +100,39 @@ int main() {
UsbHidKeyboard usb_hid_keyboard(
/*vendor_id=*/0x6666, /*product_id=*/0x2025,
/*version=*/0x0109, /*vendor_name=*/"Gboard DIY prototype",
/*product_name=*/"Gboard Dial version", /*version_name=*/"9 Dial");
/*product_name=*/"Gboard Dial version", /*version_name=*/"9 Dial rev2");
usb_hid_keyboard.SetAutoKeyRelease(true);
// Wait for a while, just in case, so that the sub-controller can be ready on
// I2C.
sleep_ms(100);
std::vector<uint8_t> i2c_buffer(2);
std::vector<uint8_t> i2c_buffer(1);
bool fn = false;
while (true) {
uint16_t motor_start_bitmap = 0;
for (size_t i = 0; i < sensors.size(); ++i) {
dials[i].Update(sensors[i].Read());
for (size_t i = 0; i < sensor_indices.size(); ++i) {
if (sensor_indices[i] < 0) {
// Read the remote sensor H value via I2C.
if (i2c.Read(68, 0, i2c_buffer)) {
dials[i].Update(i2c_buffer[0]);
}
} else {
// Read one of the local sensors.
dials[i].Update(sensors[sensor_indices[i]].Read());
}
if (!dials[i].IsBasePosition()) {
motor_start_bitmap |= (1 << i);
}
}
// Read the remote sensor H value via I2C.
bool rc = i2c.Read(68, 0, std::span<uint8_t>({i2c_buffer.data(), 1}));
if (rc) {
dials[8].Update(i2c_buffer[0]);
if (!dials[8].IsBasePosition()) {
motor_start_bitmap |= (1 << 8);
}
}
// Drive all motors via I2C.
// Use non-burst mode for better stability.
i2c_buffer[0] = motor_start_bitmap & 0xff;
i2c_buffer[1] = motor_start_bitmap >> 8;
rc = i2c.Write(68, 0, i2c_buffer);
i2c.Write(68, 0, i2c_buffer);
i2c_buffer[0] = motor_start_bitmap >> 8;
i2c.Write(68, 1, i2c_buffer);
// Check all dials to see if we have pending inputs to send over USB HID.
for (size_t i = 0; i < dials.size(); ++i) {

View File

@@ -14,12 +14,16 @@
#include "../common/usage_tables.h"
#include "../common/usb_hid_keyboard.h"
#define MOTOR_DIRECTION MotorController::Direction::kForward
//#define MOTOR_DIRECTION MotorController::Direction::kBackward
int main() {
// GPIO0 and 1 are used for stdout, and stdin by default.
stdio_init_all();
// GPIO17, 18, 19, and 20 are used for motor phase control.
MotorController motor_controller(MotorController::Mode::k1Motor);
MotorController motor_controller(MotorController::Mode::k1Motor,
MOTOR_DIRECTION);
// GPIO2, 3, 4, 5, 6, and 7 are used for 6bit photo sensing.
PhotoSensor photo_sensor(2, 3, 4, 5, 6, 7);

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -24,7 +24,6 @@ if (EXISTS ${picoVscode})
endif()
# ====================================================================================
set(PICO_BOARD none CACHE STRING "Board type")
#set(PICO_BOARD pico CACHE STRING "Board type")
# Pull in Raspberry Pi Pico SDK (must be before project)
include(pico_sdk_import.cmake)

View File

@@ -14,9 +14,13 @@
#include "../common/photo_sensor.h"
#include "i2c_device.h"
#define MOTOR_DIRECTION MotorController::Direction::kForward
//#define MOTOR_DIRECTION MotorController::Direction::kBackward
namespace {
MotorController motor_controller;
MotorController motor_controller(MotorController::Mode::k9Motor,
MOTOR_DIRECTION);
PhotoSensor sensor_h(26, 27);
uint8_t i2c_reader(uint8_t address) {