FPGA SDR(25)タッチセンサーで選局、音量調節
2018/12/15 追記:タッチセンサーの処理を修正しました。
2018/07/15 追記:NVSに選局、音量調節の状態を保持するようにしました。
ESP32単体でFPGA内のAvalonバスを操作できるAvalonPacketライブラリを作ったので、ESP32のタッチセンサーを使って選局、音量調節をできるようにしました。ESP32から4本の配線(緑色)をプラケースの外に引き出しただけです。メカスイッチだといつも固定方法に悩みますがタッチセンサーは楽ちんです。
使っているESP32は、10本のタッチセンサーT0~T9の内、T1、T2、T5がほかの用途に使われているためタッチセンサーとしては機能しませんでした。FPGAラジオには選局にT4、T6を、音量調節にT8、T9を使っています。
選局は、周波数からNCOの設定値を計算してFPGA内のAvalonバス上のPIO(アドレス0x10)に書き込みます。
音量調節は、PIO(アドレス0x0)に書き込んでI2S DACの出力レベルを操作します。
#include <SPI.h> #include <AvalonPacket.h> #include <Wire.h> #include "SSD1306Wire.h" #include <nvs.h> uint8_t volume = 0; uint8_t station = 0; const int NUM_STATIONS = 10; unsigned long freq[NUM_STATIONS] = { 594000, 810000, 954000, 1134000, 80000000, 81300000, 82500000, 90500000, 91600000, 93000000 }; String freqString[NUM_STATIONS] = { "594 kHz", "810 kHz", "954 kHz", "1134 kHz", "80.0 MHz", "81.3 MHz", "82.5 MHz", "90.5 MHz", "91.6 MHz", "93.0 MHz" }; String stationName[NUM_STATIONS] = { "NHK", "AFN", "TBS", "JOQR", "TOKYO FM", "J-WAVE", "NHK FM", "TBS FM", "JOQR FM", "NIPPON FM" }; SSD1306Wire display(0x3c, 21, 22); void printBytes(byte *bytes, int bytesSize); nvs_handle handle = 0;; AvalonPacket ap = AvalonPacket(); byte response[4]; int responseSize; int threshold = 60; volatile unsigned long touchMillis = 0; volatile int touchId = 0; void gotTouch(int id) { touchAttachInterrupt(T4, dummy, 0); touchAttachInterrupt(T6, dummy, 0); touchAttachInterrupt(T8, dummy, 0); touchAttachInterrupt(T9, dummy, 0); touchMillis = millis(); touchId = id; } void dummy() { } void gotTouch1() { if (touchRead(T4) < threshold) { gotTouch(1); } } void gotTouch2() { if (touchRead(T6) < threshold) { gotTouch(2); } } void gotTouch3() { if (touchRead(T8) < threshold) { gotTouch(3); } } void gotTouch4() { if (touchRead(T9) < threshold) { gotTouch(4); } } void setup() { Serial.begin(57600); display.init(); display.flipScreenVertically(); nvs_open("FPGA Radio", NVS_READWRITE, &handle); if (handle != 0) { nvs_get_u8(handle, "volume", &volume); nvs_get_u8(handle, "station", &station); } if (15 < volume) volume = 15; if (NUM_STATIONS-1 < station) station = NUM_STATIONS-1; delay(1000); // Wait until FPGA is configured sendVolume(volume); sendFreq(freq[station]); updateDisplay(); touchAttachInterrupt(T4, gotTouch1, threshold); touchAttachInterrupt(T6, gotTouch2, threshold); touchAttachInterrupt(T8, gotTouch3, threshold); touchAttachInterrupt(T9, gotTouch4, threshold); } void loop() { if (touchId > 0) { Serial.print("Touch: "); Serial.println(touchId); if (touchId == 1) { if (station > 0) { station -= 1; } else { station = NUM_STATIONS-1; } } else if (touchId == 2) { if (station < NUM_STATIONS-1) { station += 1; } else { station = 0; } } else if (touchId == 3) { if (volume > 0) { volume -= 1; } } else if (touchId == 4) { if (volume < 15) { volume += 1; } } sendFreq(freq[station]); sendVolume(volume); if (handle != 0) { nvs_set_u8(handle, "station", station); nvs_set_u8(handle, "volume", volume); } updateDisplay(); touchId = -1; } else if (touchId < 0 && touchMillis + 300 < millis()) { touchId = 0; touchAttachInterrupt(T4, gotTouch1, threshold); touchAttachInterrupt(T6, gotTouch2, threshold); touchAttachInterrupt(T8, gotTouch3, threshold); touchAttachInterrupt(T9, gotTouch4, threshold); } } void updateDisplay() { display.clear(); display.setFont(ArialMT_Plain_24); display.drawString(0, 0, stationName[station]); display.drawString(0, 24, freqString[station]); display.setFont(ArialMT_Plain_24); String str = ""; for (int i = 0; i < volume; i++) { str += "*"; } display.drawString(0, 48, str); display.display(); } void sendVolume(unsigned long volume) { // 0 - 15 responseSize = ap.write(0, volume, response); //ap.printBytes(response, responseSize); } void sendFreq(unsigned long freq) { // in Hz unsigned long refFreq = 1000000; // 1MHz unsigned long refValue = 58236845; // NCO phase increment if (freq >= 73750000) // 73.75MHz freq -= 73750000; unsigned long data = (unsigned long)((double)freq / (double)refFreq * (double)refValue); responseSize = ap.write(0x10, data, response); //ap.printBytes(response, responseSize); }