diff --git a/README.md b/README.md index a9c292b79e..0001ff98e9 100644 --- a/README.md +++ b/README.md @@ -768,109 +768,110 @@ your specific needs. ADS7843 ADS816x +ADS868X AMS5915 APA102 AS5047 -AS5600 +AS5600 AT24MAC402 SPI Flash BME280 BMI088 BMP085 -BNO055 +BNO055 CAT24AA CYCLE-COUNTER DRV832X DS1302 DS1631 -DS18B20 +DS18B20 DW3110 EA-DOG Encoder Input Encoder Input BitBang Encoder Output BitBang -FT245 +FT245 FT6x06 Gpio Sampler HCLAx HD44780 HMC58x -HMC6343 +HMC6343 HX711 I2C-EEPROM ILI9341 IS31FL3733 ITG3200 -IXM42XXX +IXM42XXX L3GD20 LAN8720A LAWICEL LIS302DL LIS3DSH -LIS3MDL +LIS3MDL LM75 LP503x LSM303A LSM6DS33 LSM6DSO -LTC2984 +LTC2984 MAX31855 MAX31865 MAX6966 MAX7219 MCP23x17 -MCP2515 +MCP2515 MCP3008 MCP7941x MCP990X MMC5603 MS5611 -MS5837 +MS5837 NOKIA5110 NRF24 TFT-DISPLAY PAT9125EL PCA8574 -PCA9535 +PCA9535 PCA9548A PCA9685 QMC5883L SH1106 SIEMENS-S65 -SIEMENS-S75 +SIEMENS-S75 SK6812 SK9822 SSD1306 ST7586S ST7789 -STTS22H +STTS22H STUSB4500 SX1276 SX128X TCS3414 TCS3472 -TLC594x +TLC594x TMP102 TMP12x TMP175 TOUCH2046 VL53L0 -VL6180 +VL6180 WS2812 diff --git a/examples/nucleo_f429zi/adc_ads868x/main.cpp b/examples/nucleo_f429zi/adc_ads868x/main.cpp new file mode 100644 index 0000000000..7aa50084c6 --- /dev/null +++ b/examples/nucleo_f429zi/adc_ads868x/main.cpp @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2021, Raphael Lehmann + * + * This file is part of the modm project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +// ---------------------------------------------------------------------------- + +#include +#include + +using namespace Board; + +using SpiMaster = SpiMaster1; +using Mosi = GpioB5; +using Miso = GpioB4; +using Sck = GpioB3; +using Cs = GpioA4; +using Rst = GpioF12; + +using Ads868x = modm::Ads868x; + +Ads868x adc{}; + +int +main() +{ + Board::initialize(); + Leds::setOutput(); + + MODM_LOG_INFO << "ADS868X Demo on Nucleo-F429ZI\n" << modm::endl; + + SpiMaster::initialize(); + SpiMaster::connect(); + + Rst::setOutput(); + Cs::setOutput(true); + + MODM_LOG_INFO << "Initializing ADC..." << modm::endl; + adc.initialize(); + + uint32_t counter(0); + + while (true) + { + Leds::write(counter % ((1 << (Leds::width+1)) - 1)); + + uint16_t result = adc.singleConversion(); + MODM_LOG_INFO.printf("ADC Manual: %05u\n", result); + + modm::delay(Button::read() ? 1ms : 500ms); + } + + return 0; +} diff --git a/examples/nucleo_f429zi/adc_ads868x/project.xml b/examples/nucleo_f429zi/adc_ads868x/project.xml new file mode 100644 index 0000000000..365e55e9b7 --- /dev/null +++ b/examples/nucleo_f429zi/adc_ads868x/project.xml @@ -0,0 +1,11 @@ + + modm:nucleo-f429zi + + + + + modm:build:scons + modm:platform:spi:1 + modm:driver:ads868x + + diff --git a/src/modm/driver/adc/ads868x.hpp b/src/modm/driver/adc/ads868x.hpp new file mode 100644 index 0000000000..02a48c112c --- /dev/null +++ b/src/modm/driver/adc/ads868x.hpp @@ -0,0 +1,274 @@ +// coding: utf-8 +// ---------------------------------------------------------------------------- +/* + * Copyright (c) 2020, Vivien Henry + * Copyright (c) 2023, Niklas Hauser + * + * This file is part of the modm project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +// ---------------------------------------------------------------------------- + +#ifndef MODM_ADS868x_HPP +#define MODM_ADS868x_HPP + +#include +#include +#include +#include + +namespace modm +{ + +/// @ingroup modm_driver_ads868x +struct ads868x +{ + enum class + Register: uint8_t + { + DEV_ID_REG = 0x00, + RST_PWRCTRL_REG = 0x04, + SDI_CTL_REG = 0x08, + SDO_CTL_REG = 0x0C, + DATAOUT_CTL_REG = 0x10, + RANGE_CTL_REG = 0x14, + ALARM_REG = 0x20, + ALARM_H_TH_REG = 0x24, + ALARM_L_TH_REG = 0x28, + }; + + + /// Device ID register + enum class + DeviceIDRegister : uint32_t + { + Addr0 = Bit16, + Addr1 = Bit17, + Addr2 = Bit18, + Addr3 = Bit19 + }; + MODM_FLAGS32(DeviceIDRegister); + + typedef modm::Value DeviceID_t; + + + // Reset and Power Control register + enum class + ResetPowerControlRegister: uint32_t + { + WKey0 = Bit8, + WKey1 = Bit9, + WKey2 = Bit10, + WKey3 = Bit11, + WKey4 = Bit12, + WKey5 = Bit13, + WKey6 = Bit14, + WKey7 = Bit15, + + VDDAlarmDisable = Bit5, + + InputAlarmDisable = Bit4, + RSTn_ApplicationReset = Bit2, + NapModeEnable = Bit1, + PowerDownEnable = Bit0 + }; + MODM_FLAGS32(ResetPowerControlRegister); + + typedef modm::Value WriteKey_t; + + // SDI Data Input Control register + enum class + SDIControlRegister: uint32_t + { + SDIMode0 = Bit0, + SDIMode1 = Bit1 + }; + MODM_FLAGS32(SDIControlRegister); + + enum class + SDIMode : uint8_t + { + Std_Pol0_Phase0 = 0, + Std_Pol0_Phase1 = 1, + Std_Pol1_Phase0 = 2, + Std_Pol1_Phase1 = 3 + }; + typedef modm::Configuration SDIMode_t; + + // SDO Data Output Control Register + enum class + SDOControlRegister: uint32_t + { + SDOMode0 = Bit0, + SDOMode1 = Bit1, + + SSyncClock = Bit6, + + SDO1Config0 = Bit8, + SDO1Config1 = Bit9, + + GPOValue = Bit12 + }; + MODM_FLAGS32(SDOControlRegister); + + enum class + SDOMode: uint8_t + { + SameAsSDI0 = 0b00, + SameAsSDI1 = 0b01, + Invalid = 0b10, + ADCMasterClk_SourcSync = 0b11 + }; + typedef modm::Configuration SDOMode_t; + + + enum class + SourceSyncClock: uint8_t + { + External = 0, + Internal = 1 + }; + typedef modm::Configuration SourceSyncClock_t; + + enum class + SDO1Config: uint8_t + { + SDO1_Tristated = 0b00, + SDO1_Alarm = 0b01, + SDO1_GPO = 0b10, + SDO1_2BitsSDO = 0b11 + }; + typedef modm::Configuration SDO1Config_t; + + + enum class + DataOutControlRegister: uint32_t + { + DataVal0 = Bit0, + DataVal1 = Bit1, + DataVal2 = Bit2, + + ParityEnable = Bit3, + + Inc_Range = Bit8, + + Inc_InActiveAlarm_High = Bit10, + Inc_InActiveAlarm1_Low = Bit11, + + Inc_VDDActiveAlarm0_High = Bit12, + Inc_VDDActiveAlarm1_Low = Bit13, + + Inc_DeviceAddr = Bit14 + }; + MODM_FLAGS32(DataOutControlRegister); + + enum class + DataValue: uint8_t + { + ConversionData = 0b000, + All0 = 0b100, + All1 = 0b101, + Seq01 = 0b110, + Seq0011 = 0b111 + }; + typedef modm::Configuration DataValue_t; + + + enum class + RangeSelectionRegister: uint32_t + { + RangeSel0 = Bit0, + RangeSel1 = Bit1, + RangeSel2 = Bit2, + RangeSel3 = Bit3, + + InternalRefDisabled = Bit6 + }; + MODM_FLAGS32(RangeSelectionRegister); + + enum class + RangeSel: uint8_t + { + Range_Bipolar_3_000_VRef = 0b0000, + Range_Bipolar_2_500_VRef = 0b0001, + Range_Bipolar_1_500_VRef = 0b0010, + Range_Bipolar_1_250_VRef = 0b0011, + Range_Bipolar_0_625_VRef = 0b0100, + Range_Unipolar_3_00_VRef = 0b1000, + Range_Unipolar_2_50_VRef = 0b1001, + Range_Unipolar_1_50_VRef = 0b1010, + Range_Unipolar_1_25_VRef = 0b1011 + }; + typedef modm::Configuration RangeSel_t; + +}; // struct ads868x + +/** + * @tparam SpiMaster SpiMaster interface + * @tparam Cs Chip-select pin + * + * @author Vivien Henry + * @ingroup modm_driver_ads868x + */ +template +class Ads868x : public ads868x, public modm::SpiDevice +{ +public: + /// Call this function once before using the device + void + initialize(); + + uint16_t + singleConversion(); + + void + setDeviceAddress(uint8_t devID) + { + writeRegister(Register::DEV_ID_REG, DeviceID_t(devID).value); + }; + + uint8_t + getDeviceAddress() + { + const uint32_t devID = readRegister(Register::DEV_ID_REG); + return DeviceID_t::get(DeviceIDRegister_t(devID)); + } + + void + setOutputProtocol(SDOMode mode, SourceSyncClock syncClock, SDO1Config sdo1Config) + { + SDOControlRegister_t sdo_reg = SDOMode_t(mode) | SourceSyncClock_t(syncClock) | SDO1Config_t(sdo1Config); + writeRegister(Register::SDO_CTL_REG, sdo_reg.value); + } + + void + setRange(RangeSel range) + { + writeRegister(Register::RANGE_CTL_REG, RangeSel_t(range).value); + } + + RangeSel + getRange() + { + const uint32_t range = readRegister(Register::RANGE_CTL_REG); + return RangeSel_t::get(RangeSelectionRegister_t(range)); + } + +private: + void + writeRegister(Register reg, uint32_t data); + + uint32_t + readRegister(Register reg); + + uint8_t buffer[4]; +}; + +} // namespace modm + +#include "ads868x_impl.hpp" + +#endif // MODM_ADS868x_HPP diff --git a/src/modm/driver/adc/ads868x.lb b/src/modm/driver/adc/ads868x.lb new file mode 100644 index 0000000000..ba79f566e6 --- /dev/null +++ b/src/modm/driver/adc/ads868x.lb @@ -0,0 +1,43 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# +# Copyright (c) 2018, Niklas Hauser +# +# This file is part of the modm project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# ----------------------------------------------------------------------------- + + +def init(module): + module.name = ":driver:ads868x" + module.description = """ +# ADS868x ADC + +ADS868x 16-Bit, High-Speed, Single-Supply, SAR ADC Data Acquisition System with +Programmable, Bipolar Input Ranges. + +This driver supports these three devices: +- ADS8681 +- ADS8685 +- ADS8689 + +[Datasheet](https://www.ti.com/lit/ds/symlink/ads8681.pdf) +""" + + +def prepare(module, options): + module.depends( + ":architecture:gpio", + ":architecture:register", + ":architecture:spi.device", + ":architecture:fiber") + return True + + +def build(env): + env.outbasepath = "modm/src/modm/driver/adc" + env.copy("ads868x.hpp") + env.copy("ads868x_impl.hpp") diff --git a/src/modm/driver/adc/ads868x_impl.hpp b/src/modm/driver/adc/ads868x_impl.hpp new file mode 100644 index 0000000000..31268895d2 --- /dev/null +++ b/src/modm/driver/adc/ads868x_impl.hpp @@ -0,0 +1,132 @@ +// coding: utf-8 +// ---------------------------------------------------------------------------- +/* + * Copyright (c) 2020, Vivien Henry + * Copyright (c) 2023, Niklas Hauser + * + * This file is part of the modm project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +// ---------------------------------------------------------------------------- + +#ifndef MODM_ADS868x_HPP +# error "Don't include this file directly! Use 'ads868x.hpp' instead." +#endif + +// ---------------------------------------------------------------------------- +namespace modm +{ + + +template +void +Ads868x::initialize() +{ + Cs::setOutput(modm::Gpio::Low); + nReset::setOutput(modm::Gpio::Low); + + modm::this_fiber::sleep_for(1ms); + + nReset::set(); + Cs::set(); +} + + +template +uint16_t +Ads868x::singleConversion() +{ + modm::this_fiber::poll([&]{ return this->acquireMaster(); }); + Cs::reset(); + + SpiMaster::transfer(nullptr, buffer, 2); + + if (this->releaseMaster()) Cs::set(); + + return uint16_t((buffer[0] << 8) | buffer[1]); +} + + +template +void +Ads868x::writeRegister(Register reg, uint32_t data) +{ + // LSB (0-15) + buffer[0] = 0b1101'0000; + buffer[1] = uint8_t(reg); + buffer[2] = data >> 8; + buffer[3] = data; + + modm::this_fiber::poll([&]{ return this->acquireMaster(); }); + Cs::reset(); + + SpiMaster::transfer(buffer, nullptr, 4); + + Cs::set(); + + // MSB (16-31) + buffer[0] = 0b1101'0000; + buffer[1] = uint8_t(reg) + 2; + buffer[2] = data >> 24; + buffer[3] = data >> 16; + + modm::this_fiber::sleep_for(1us); + Cs::reset(); + + SpiMaster::transfer(buffer, nullptr, 4); + + if (this->releaseMaster()) Cs::set(); +} + +template +uint32_t +Ads868x::readRegister(Register reg) +{ + uint32_t result{}; + + modm::this_fiber::poll([&]{ return this->acquireMaster(); }); + Cs::reset(); + + // MSB (31-16) + buffer[0] = 0b1100'1000; + buffer[1] = uint8_t(reg) + 2; + buffer[2] = 0; + buffer[3] = 0; + + SpiMaster::transfer(buffer, nullptr, 4); + + Cs::set(); + modm::this_fiber::sleep_for(1us); + Cs::reset(); + + SpiMaster::transfer(nullptr, buffer, 4); + result = (uint32_t(buffer[0]) << 24) | (uint32_t(buffer[1]) << 16); + + Cs::set(); + modm::this_fiber::sleep_for(1us); + Cs::reset(); + + // LSB (0-15) + buffer[0] = 0b1100'1000; + buffer[1] = uint8_t(reg); + buffer[2] = 0; + buffer[3] = 0; + + SpiMaster::transfer(buffer, nullptr, 4); + + Cs::set(); + modm::this_fiber::sleep_for(1us); + Cs::reset(); + + SpiMaster::transfer(nullptr, buffer, 4); + result |= (uint32_t(buffer[0]) << 8) | uint32_t(buffer[1]); + + if (this->releaseMaster()) Cs::set(); + + return result; +} + +} // namespace modm