質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
組み込み開発

組み込み開発とは、スマートフォンや家電、自動車などに組み込まれているコンピューターシステムの開発のことです。特定の用途に特化しており、限られた機能のための開発を指します。組み込み開発で作られた機器を組み込み機器と呼び、近年ではPCのオペレーションシステム(OS)にも採用されています。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Arduino

Arduinoは、AVRマイコン、単純なI/O(入出力)ポートを備えた基板、C言語を元としたArduinoのプログラム言語と、それを実装した統合開発環境から構成されたシステムです。

Q&A

解決済

1回答

599閲覧

SPIクラスを継承したクラスでSPI ADCの値が取得できない

tain

総合スコア241

組み込み開発

組み込み開発とは、スマートフォンや家電、自動車などに組み込まれているコンピューターシステムの開発のことです。特定の用途に特化しており、限られた機能のための開発を指します。組み込み開発で作られた機器を組み込み機器と呼び、近年ではPCのオペレーションシステム(OS)にも採用されています。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Arduino

Arduinoは、AVRマイコン、単純なI/O(入出力)ポートを備えた基板、C言語を元としたArduinoのプログラム言語と、それを実装した統合開発環境から構成されたシステムです。

0グッド

0クリップ

投稿2022/09/28 15:08

編集2022/10/06 14:48

前提

ArduinoとSPI接続ADC(MCP3008)を接続し、ADCの値を取得するクラスを作成したいです。
SPIライブラリを用いた動作はうまくいったので、SPISettingクラスを継承してCS端子の管理やチャンネルの設定などを行うクラスを作っています。

質問

プログラムを動かしたところ、SPIで値が取得できず無限ループ状態になっているようでした。オシロスコープで計測したところ、CSピンがLowに落ちたままでクロックがでていないことを確認しています。

当該プログラム

cpp:mcp3008.h

1/* */ 2#ifndef __MCP3008_H__ 3#define __MCP3008_H__ 4#include <arduino.h> 5#include <stdint.h> 6#include <SPI.h> 7 8class ADC_MCP3008 : public SPISettings 9{ 10 using SPISettings::SPISettings; 11 public: 12 ADC_MCP3008(uint8_t CSPinNo, uint32_t clock) 13 : m_ADC_MCP3008Setting(clock, MSBFIRST, SPI_MODE0) 14 , m_CSPinNumber(CSPinNo) 15 { 16 pinMode(m_CSPinNumber, OUTPUT); 17 digitalWrite(m_CSPinNumber, m_CSPIN_NEGATE); 18 } 19 virtual ~ADC_MCP3008() 20 { 21 } 22 uint16_t readSingleMode(uint8_t ch); 23 uint16_t readDifferentialMode(uint8_t ch); 24 uint32_t readTest(void); 25 uint32_t privateRead(void); 26 void readBurstSingleMode(uint16_t * buffer); 27 void readBurstDifferentialMode(uint16_t * buffer); 28 private: 29 const SPISettings m_ADC_MCP3008Setting; 30 const uint8_t m_CSPinNumber; 31 const uint8_t m_CSPIN_ASSERT = LOW; 32 const uint8_t m_CSPIN_NEGATE = HIGH; 33 const uint8_t m_ADC_CHNUM = 8; 34 uint32_t _readRaw(uint8_t dummy, uint8_t highByte, uint8_t lowByte); 35}; 36 37#endif /* __MCP300x_H__ */

cpp:mcp3008.cpp

1#include <arduino.h> 2#include <stdint.h> 3#include <SPI.h> 4#include "mcp3008.h" 5 6uint32_t ADC_MCP3008::_readRaw(uint8_t startByte, uint8_t highByte, uint8_t lowByte) 7{ 8 volatile uint8_t rcvs[3]; 9 digitalWrite(m_CSPinNumber, m_CSPIN_ASSERT); 10 rcvs[0] = SPI.transfer(startByte); 11 rcvs[1] = SPI.transfer(highByte); 12 rcvs[2] = SPI.transfer(lowByte); 13 digitalWrite(m_CSPinNumber, m_CSPIN_NEGATE); 14 return (uint32_t)((rcvs[0] << 16) & (rcvs[1] << 8) & (rcvs[2])); 15} 16 17uint16_t ADC_MCP3008::readSingleMode(uint8_t ch) 18{ 19 uint16_t rcv; 20 if (ch < m_ADC_CHNUM) 21 { 22 SPI.beginTransaction(m_ADC_MCP3008Setting); 23 rcv = _readRaw(0x01, (uint8_t)( 0x80 | (ch << 4)), 0x00); 24 SPI.endTransaction(); 25 } 26 else 27 { 28 rcv = 0xFFFF; 29 } 30 return rcv; 31} 32 33uint16_t ADC_MCP3008::readDifferentialMode(uint8_t ch) 34{ 35} 36 37void ADC_MCP3008::readBurstSingleMode(uint16_t * buffer) 38{ 39} 40 41void ADC_MCP3008::readBurstDifferentialMode(uint16_t * buffer) 42{ 43 44} 45 46uint32_t ADC_MCP3008::readTest(void) 47{ 48 SPI.beginTransaction(m_ADC_MCP3008Setting); 49 return _readRaw(0x01, 0x80, 0x00); 50 SPI.endTransaction(); 51} 52 53uint32_t ADC_MCP3008::privateRead(void) 54{ 55 digitalWrite(m_CSPinNumber, m_CSPIN_ASSERT); 56 delay(10); 57 digitalWrite(m_CSPinNumber, m_CSPIN_NEGATE); 58 return m_CSPinNumber; 59} 60

cpp:mcp3004_3008.ino

1#include <arduino.h> 2#include "mcp3008.h" 3 4#define CSPIN A4 5 6 7ADC_MCP3008 spiADC = ADC_MCP3008(CSPIN, 1000000); 8 9void setup() 10{ 11 Serial.begin(115200); 12 Serial.println("MCP3004_3008_TEST"); 13 delay(100); 14} 15 16void loop() 17{ 18 uint32_t readval; 19 // readval = spiADC.readSingleMode(0); 20 readval = spiADC.readTest(); 21 // readval = 10; 22 ///readval = spiADC.privateRead(); 23 Serial.print(millis()); 24 Serial.print(", "); 25 Serial.print(readval); 26 Serial.println(); 27 delay(10); 28}

試したこと

readSingleModeではうまく通信ができていないので、readTestで送信値を固定して送信してみましたがだめでした。また、
コンストラクタでの初期化がうまくいっている事を確認するため、privateRead関数内でCSを動かしたところ、正しく動いているようです。

補足情報(FW/ツールのバージョンなど)

cpp:readok.ino

1#include <SPI.h> 2#define CSPIN A4 3float Vref = 5.0 ; 4 5SPISettings settings(1000000,MSBFIRST,SPI_MODE0); 6 7void setup() { 8 pinMode(SS, OUTPUT); 9 Serial.begin(9600); 10 SPI.begin(); 11} 12 13void loop(){ 14 SPI.beginTransaction(settings); 15 digitalWrite(SS, LOW); 16 SPI.transfer(0b00000001); // Start bit 1 17 byte highByte = SPI.transfer(0b10000000); // CH0 singleEnd 18 byte lowByte = SPI.transfer(0x00); // dummy 19 digitalWrite(SS, HIGH); 20 SPI.endTransaction(); 21 unsigned int dataCh0 = ((highByte & 0x03) << 8) + lowByte; 22 float volts = dataCh0*Vref /1024; 23 Serial.println("highByte= " + String(highByte,DEC) + "lowByte= " + String(lowByte,DEC) ); 24 Serial.println("CH0 " + String(volts,3) + "V"); 25}

参考にしたHP。こちらのプログラムは動作することを確認しました。

解決

皆様のご指摘を参考にしつつ、それ以外のバグも見つけ解決しました。

cpp:mcp3008.h

1#ifndef __MCP3009_H__ 2#define __MCP3008_H__ 3#include <arduino.h> 4#include <stdint.h> 5#include <SPI.h> 6 7class ADC_MCP3008 8{ 9 public: 10 ADC_MCP3008(uint8_t CSPinNo, uint32_t clock, float vref) 11 : m_ADC_MCP3008Setting(clock, MSBFIRST, SPI_MODE0) 12 , m_CSPinNumber(CSPinNo) 13 , ADC_VREF(vref) 14 { 15 SPI.begin(); 16 pinMode(m_CSPinNumber, OUTPUT); 17 digitalWrite(m_CSPinNumber, m_CSPIN_NEGATE); 18 } 19 virtual ~ADC_MCP3008() 20 { 21 } 22 uint16_t readSingleMode(uint8_t ch); 23 uint16_t readDifferentialMode(uint8_t ch); 24 void readBurstSingleMode(uint16_t * buffer); 25 void readBurstDifferentialMode(uint16_t * buffer); 26 float convertBinToVoltage(uint16_t bin); 27 const uint8_t ADC_SINGLE_CHNUM = 8; 28 const uint8_t ADC_DUAL_CHNUM = 4; 29 const float ADC_VREF; 30 private: 31 const SPISettings m_ADC_MCP3008Setting; 32 const uint8_t m_CSPinNumber; 33 const uint8_t m_CSPIN_ASSERT = LOW; 34 const uint8_t m_CSPIN_NEGATE = HIGH; 35 const uint16_t m_ADC_MASK = 0x03FF; // 10bit 36 const uint8_t m_ADC_STARTBIT = 0x01; // 0b0000 0001 37 const uint8_t m_ADC_SINGLMODE = 0x80; // 0b1000 0000 38 const uint8_t m_ADC_DUALMODE = 0x00; // 0b0000 0000 39 uint32_t _readRaw(uint8_t startByte, uint8_t highByte, uint8_t lowByte); 40}; 41 42#endif /* __MCP300x_H__ */

cpp:mcp3008.cpp

1#include <arduino.h> 2#include <stdint.h> 3#include <SPI.h> 4#include "mcp3008.h" 5 6uint32_t ADC_MCP3008::_readRaw(uint8_t startByte, uint8_t highByte, uint8_t lowByte) 7{ 8 volatile uint8_t rcvs[3]; 9 digitalWrite(m_CSPinNumber, m_CSPIN_ASSERT); 10 rcvs[0] = SPI.transfer(startByte); 11 rcvs[1] = SPI.transfer(highByte); 12 rcvs[2] = SPI.transfer(lowByte); 13 digitalWrite(m_CSPinNumber, m_CSPIN_NEGATE); 14 return (uint32_t)((rcvs[0] << 16) | (rcvs[1] << 8) | (rcvs[2])); 15} 16 17uint16_t ADC_MCP3008::readSingleMode(uint8_t ch) 18{ 19 uint16_t rcv; 20 if (ch < ADC_SINGLE_CHNUM) 21 { 22 SPI.beginTransaction(m_ADC_MCP3008Setting); 23 rcv = (uint16_t)( _readRaw(m_ADC_STARTBIT, (uint8_t)( m_ADC_SINGLMODE | (ch << 4)), 0x00) & m_ADC_MASK); 24 SPI.endTransaction(); 25 } 26 else 27 { 28 rcv = 0xFFFF; 29 } 30 return rcv; 31} 32 33uint16_t ADC_MCP3008::readDifferentialMode(uint8_t ch) 34{ 35 uint16_t rcv; 36 if (ch < ADC_DUAL_CHNUM) 37 { 38 SPI.beginTransaction(m_ADC_MCP3008Setting); 39 rcv = (uint16_t)(_readRaw(m_ADC_STARTBIT, (uint8_t)( m_ADC_DUALMODE| (ch << 4)), 0x00)) & m_ADC_MASK; 40 SPI.endTransaction(); 41 } 42 else 43 { 44 rcv = 0xFFFF; 45 } 46 return rcv; 47} 48 49void ADC_MCP3008::readBurstSingleMode(uint16_t * buffer) 50{ 51 int cnt; 52 SPI.beginTransaction(m_ADC_MCP3008Setting); 53 for (cnt = 0; cnt < ADC_SINGLE_CHNUM; cnt++, buffer++) 54 { 55 *buffer = (uint16_t)(_readRaw(m_ADC_STARTBIT, (uint8_t)( m_ADC_SINGLMODE | (cnt << 4)), 0x00)) & m_ADC_MASK; 56 } 57 SPI.endTransaction(); 58} 59 60void ADC_MCP3008::readBurstDifferentialMode(uint16_t * buffer) 61{ 62 int cnt; 63 SPI.beginTransaction(m_ADC_MCP3008Setting); 64 for (cnt = 0; cnt < ADC_DUAL_CHNUM; cnt++, buffer++) 65 { 66 *buffer = (uint16_t)(_readRaw(m_ADC_STARTBIT, (uint8_t)( m_ADC_DUALMODE| (cnt << 4)), 0x00)) & m_ADC_MASK; 67 } 68 SPI.endTransaction(); 69} 70 71float ADC_MCP3008::convertBinToVoltage(uint16_t bin) 72{ 73 return (float)bin * ADC_VREF / m_ADC_MASK; 74}

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

thkana

2022/09/28 22:49

SPI.begin()は呼ばれていなくていいんだっけ?
tain

2022/09/28 23:50

確かにSPISettingを使っているので、SPI.beginは不要です。ただ、readTestのbeginTransactionは抜けてますね。お恥ずかしい。残念ながら追加してもだめでした。
matukeso

2022/09/29 02:15

メンバにSPISettings m_ADC_MCP3008Setting;を持ってるなら、SPISettingsを継承する意味がないような。 >SPISettingを使っているので、SPI.beginは不要 というのも、根拠がよくわかりませんが、、
thkana

2022/09/29 12:28

> 確かにSPISettingを使っているので、SPI.beginは不要です いやいや、そんなことはないでしょう。とりあえずArduino UNOとして、SPIClass::begin()の中で SPCR |= _BV(MSTR); SPCR |= _BV(SPE); とかやっているのはやっぱりなきゃダメでしょう。 そもそもが SPISettingじゃなくてSPIClassを継承する話なんじゃないかしら、とか思ったりして。
guest

回答1

0

自己解決

SPI.begin()を正しく呼ぶこと。ビット演算のミスを見つけ自己解決しました。

投稿2022/10/06 05:48

tain

総合スコア241

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問