[cxx]: simple spi master class

* spi cxx unit test (CATCH-based, on host)
* added portmacro.h to driver mocking
* added simple testing app to write/read SPI,
  using an MPU9250
This commit is contained in:
Jakob Hasse
2021-10-25 14:56:59 +08:00
parent c499fe5fa5
commit 7efb01846f
35 changed files with 2154 additions and 52 deletions
@@ -0,0 +1,8 @@
# The following lines of boilerplate have to be in your project's CMakeLists
# in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.5)
set(EXTRA_COMPONENT_DIRS "$ENV{IDF_PATH}/examples/cxx/experimental/experimental_cpp_component")
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(simple_spi_rw_example)
@@ -0,0 +1,68 @@
# Example: C++ SPI sensor read for MCU9250 inertial/giroscope sensor
(See the README.md file in the upper level 'examples' directory for more information about examples.)
This example demonstrates usage of C++ SPI classes in ESP-IDF to read the `WHO_AM_I` register of the sensor.
In this example, the `sdkconfig.defaults` file sets the `CONFIG_COMPILER_CXX_EXCEPTIONS` option.
This enables both compile time support (`-fexceptions` compiler flag) and run-time support for C++ exception handling.
This is necessary for the C++ SPI API.
## How to use example
### Hardware Required
An MCU9250 sensor and any commonly available ESP32 development board.
### Configure the project
```
idf.py menuconfig
```
### Build and Flash
```
idf.py -p PORT flash monitor
```
(Replace PORT with the name of the serial port.)
(To exit the serial monitor, type ``Ctrl-]``.)
See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.
## Example Output
If the sensor is read correctly:
```
...
I (0) cpu_start: Starting scheduler on APP CPU.
Result of WHO_AM_I register: 0x71
I (437) gpio: GPIO[23]| InputEn: 0| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0
I (447) gpio: GPIO[25]| InputEn: 0| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0
I (457) gpio: GPIO[26]| InputEn: 0| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0
I (467) gpio: GPIO[27]| InputEn: 0| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0
Done
```
If there's an error with the SPI peripheral:
```
...
I (0) cpu_start: Starting scheduler on APP CPU.
E (434) spi: spicommon_bus_initialize_io(429): mosi not valid
Coulnd't read SPI!
```
If the SPI pins are not connected properly, the resulting read may just return 0, this error can not be detected:
```
...
I (0) cpu_start: Starting scheduler on APP CPU.
Result of WHO_AM_I register: 0x00
I (437) gpio: GPIO[23]| InputEn: 0| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0
I (447) gpio: GPIO[25]| InputEn: 0| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0
I (457) gpio: GPIO[26]| InputEn: 0| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0
I (467) gpio: GPIO[27]| InputEn: 0| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0
```
@@ -0,0 +1,3 @@
idf_component_register(SRCS "simple_spi_rw_example.cpp"
INCLUDE_DIRS "."
REQUIRES experimental_cpp_component)
@@ -0,0 +1,4 @@
#
# "main" pseudo-component makefile.
#
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
@@ -0,0 +1,48 @@
/*
* SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: CC0
*
* MPU9250 SPI Sensor C++ Example
*
* This example code is in the Public Domain (or CC0 licensed, at your option.)
*
* Unless required by applicable law or agreed to in writing, this
* software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, either express or implied.
*/
#include <iostream>
#include "spi_host_cxx.hpp"
using namespace std;
using namespace idf;
static const GPIONum NSS(23);
static const uint8_t READ_FLAG = 0x80;
static const uint8_t MPU9250_WHO_AM_I_REG_ADDR = 0x75;
extern "C" void app_main(void)
{
try {
SPIMaster master(SPINum(2),
MOSI(25),
MISO(26),
SCLK(27));
shared_ptr<SPIDevice> spi_dev = master.create_dev(CS(NSS.get_num()), Frequency::MHz(1));
vector<uint8_t> write_data = {MPU9250_WHO_AM_I_REG_ADDR | READ_FLAG, 0x00};
vector<uint8_t> result = spi_dev->transfer(write_data).get();
cout << "Result of WHO_AM_I register: 0x";
printf("%02X", result[1]);
cout << endl;
this_thread::sleep_for(std::chrono::seconds(2));
} catch (const SPIException &e) {
cout << "Coulnd't read SPI!" << endl;
}
}
@@ -0,0 +1,3 @@
# Enable C++ exceptions and set emergency pool size for exception objects
CONFIG_COMPILER_CXX_EXCEPTIONS=y
CONFIG_COMPILER_CXX_EXCEPTIONS_EMG_POOL_SIZE=1024