Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/thirdpin/libopencm3_cpp_extensions.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnastasiia Lazareva <n_lazareva@mail.ru>2017-08-09 22:22:40 +0300
committerAnastasiia Lazareva <n_lazareva@mail.ru>2017-08-09 22:22:40 +0300
commitec59ef55760d9ade58c667d35650a4d5363ccf7b (patch)
treed857fd7c8869f6f6745f233304725a23298985db
parent81c1e0cc7a8e23f1b786c486d626a3d150ffa2bd (diff)
IMPR: One Wire interface added to the library. it's not a part of the stm peripheral, so the source files are in /extra folder.
-rw-r--r--cm3cpp_i2c.cpp2
-rw-r--r--cm3cpp_i2c.h4
-rw-r--r--extra/one_wire.cpp324
-rw-r--r--extra/one_wire.h60
-rw-r--r--utils/round_buffer.h7
5 files changed, 390 insertions, 7 deletions
diff --git a/cm3cpp_i2c.cpp b/cm3cpp_i2c.cpp
index da717f0..316a722 100644
--- a/cm3cpp_i2c.cpp
+++ b/cm3cpp_i2c.cpp
@@ -53,7 +53,7 @@ I2c::I2c(Config i2c_conf)
#ifndef FREERTOS
_counter_ms->init(systick::Counter::Mode::ONE_SHOT, MAX_TRANSMIT_TIME_MS);
#else
- _counter_ms = new timers::I2cTimer(MAX_TRANSMIT_TIME_MS);
+ _counter_ms = new timers::OneShotTimer(MAX_TRANSMIT_TIME_MS);
#endif
}
diff --git a/cm3cpp_i2c.h b/cm3cpp_i2c.h
index 19f9897..4858720 100644
--- a/cm3cpp_i2c.h
+++ b/cm3cpp_i2c.h
@@ -35,7 +35,7 @@ I2C C++ Wrapper of libopencm3 library for STM32F2, STM32F4
#ifndef FREERTOS
#include "systick_ext.h"
#else
-#include <timers/I2cTimer.hpp>
+#include <timers/OneShotTimer.hpp>
#endif
namespace cm3cpp {
@@ -197,7 +197,7 @@ private:
#ifndef FREERTOS
systick::Counter *_counter_ms;
#else
- timers::I2cTimer *_counter_ms;
+ timers::OneShotTimer *_counter_ms;
#endif
void _send_start();
diff --git a/extra/one_wire.cpp b/extra/one_wire.cpp
new file mode 100644
index 0000000..69189af
--- /dev/null
+++ b/extra/one_wire.cpp
@@ -0,0 +1,324 @@
+#include "one_wire.h"
+
+namespace cm3cpp {
+
+namespace extra {
+
+OneWire::OneWire(gpio::Pinout p, uint8_t tim_number, uint32_t tim_presc) :
+ _pinout(p), _timer(new tim::Timer(tim_number))
+{
+ _timer->set_counter_direction(tim::CounterDirection::UP);
+ _timer->set_alignment(tim::Alignment::EDGE);
+ _timer->set_clock_division(tim::ClockDivision::TIMER_CLOCK_MUL_1);
+ _timer->set_prescaler_value(tim_presc);
+ _timer->set_counter_mode(tim::CounterMode::CONTINUOUS);
+ _timer->disable_autoreload_preload();
+ _timer->set_counter_value(0);
+
+ _last_discrepancy = 0;
+ _last_device = false;
+ _last_family_discrepancy = 0;
+}
+
+uint8_t OneWire::read_byte(void)
+{
+ uint8_t data = 0;
+
+ for (uint8_t bit_count = 0; bit_count < 8; bit_count++)
+ {
+ /*pull low to initiate read*/
+ _pinout.mode_setup(gpio::Mode::OUTPUT, gpio::PullMode::PULL_UP);
+ _pinout.set_output_options(gpio::OutputType::OPEN_DRAIN, gpio::Speed::FAST_50MHz);
+ _pinout.clear();
+ _wait(_LOW_PULSE_TIME_US);
+
+ /*float high*/
+ _pinout.mode_setup(gpio::Mode::INPUT, gpio::PullMode::PULL_UP);
+ _wait(_READ_SAMPLE_WAIT_US);
+
+ /*sample bus and shift into msb*/
+ data = data >> 1;
+ if (_pinout.get() != 0)
+ data |= 0x80;
+
+ /*wait until end of time slot*/
+ _wait(_END_READ_SLOT_WAIT_US);
+ }
+
+ return data;
+}
+
+void OneWire::write_byte(uint8_t data)
+{
+ for (uint8_t bit_count = 0; bit_count < 8; bit_count++)
+ {
+ /*pull low to initiate write*/
+ _pinout.mode_setup(gpio::Mode::OUTPUT, gpio::PullMode::PULL_UP);
+ _pinout.set_output_options(gpio::OutputType::OPEN_DRAIN, gpio::Speed::FAST_50MHz);
+ _pinout.clear();
+ _wait(_LOW_PULSE_TIME_US);
+
+ /*write next bit*/
+ ((bool)(data & 0x01)) ? _pinout.set() : _pinout.clear();
+ data = data >> 1;
+
+ /*wait until end of slot*/
+ _wait(_WRITE_SLOT_WAIT_US);
+
+ /*float high and let device recover*/
+ _pinout.mode_setup(gpio::Mode::INPUT, gpio::PullMode::PULL_UP);
+ _wait(_RECOVERY_TIME_US);
+ }
+}
+
+bool OneWire::read_bit(void)
+{
+ bool bit;
+
+ /*pull low to initiate read*/
+ _pinout.mode_setup(gpio::Mode::OUTPUT, gpio::PullMode::PULL_UP);
+ _pinout.set_output_options(gpio::OutputType::OPEN_DRAIN, gpio::Speed::FAST_50MHz);
+ _pinout.clear();
+
+ _wait(_LOW_PULSE_TIME_US);
+
+ /*float high*/
+ _pinout.mode_setup(gpio::Mode::INPUT, gpio::PullMode::PULL_UP);
+ _wait(_READ_SAMPLE_WAIT_US);
+
+ /*sample bus*/
+ if (_pinout.get() > 0)
+ bit = true;
+ else
+ bit = false;
+
+ /*wait until end of time slot*/
+ _wait(_END_READ_SLOT_WAIT_US);
+
+ return bit;
+}
+
+void OneWire::write_bit(bool bit)
+{
+ /*pull low to initiate write*/
+ _pinout.mode_setup(gpio::Mode::OUTPUT, gpio::PullMode::PULL_UP);
+ _pinout.set_output_options(gpio::OutputType::OPEN_DRAIN, gpio::Speed::FAST_50MHz);
+ _pinout.clear();
+
+ _wait(_LOW_PULSE_TIME_US);
+
+ /*write next bit*/
+ bit ? _pinout.set() : _pinout.clear();
+
+ /*wait until end of slot*/
+ _wait(_WRITE_SLOT_WAIT_US);
+
+ /*float high and let device recover*/
+ _pinout.mode_setup(gpio::Mode::INPUT, gpio::PullMode::PULL_UP);
+ _wait(_RECOVERY_TIME_US);
+}
+
+bool OneWire::touch_reset(void)
+{
+ bool presence = false;
+ char sample_count = (_RESET_PULSE_TIME_US / 8);
+
+ /*low reset pulse*/
+ _pinout.mode_setup(gpio::Mode::OUTPUT, gpio::PullMode::PULL_UP);
+ _pinout.set_output_options(gpio::OutputType::OPEN_DRAIN, gpio::Speed::FAST_50MHz);
+ _pinout.clear();
+ _wait(_RESET_PULSE_TIME_US);
+
+ /*float high*/
+ _pinout.mode_setup(gpio::Mode::INPUT, gpio::PullMode::PULL_UP);
+
+ while (sample_count-- != 0)
+ {
+ _wait(8);
+
+ /*sample bus to check for connected devices*/
+ if (_pinout.get() == 0)
+ presence = true;
+ }
+
+ return presence;
+}
+
+bool OneWire::search_first(bool do_reset, bool alarm_only)
+{
+ _last_discrepancy = 0;
+ _last_device = false;
+ _last_family_discrepancy = 0;
+ return search_next(do_reset, alarm_only);
+}
+
+bool OneWire::search_next(bool do_reset, bool alarm_only)
+{
+ uint8_t bit_test, search_direction, bit_number;
+ uint8_t last_zero, serial_byte_number;
+ uint8_t serial_byte_mask;
+ uint8_t lastcrc8 = 0;
+
+ // initialize for search
+ bit_number = 1;
+ last_zero = 0;
+ serial_byte_number = 0;
+ serial_byte_mask = 1;
+ bool next_result = 0;
+
+ // if the last call was not the last one
+ if (!_last_device)
+ {
+ // check if reset first is requested
+ if (do_reset)
+ {
+ // reset the 1-wire
+ // if there are no parts on 1-wire, return FALSE
+ if (!touch_reset())
+ {
+ _last_discrepancy = 0;
+ _last_family_discrepancy = 0;
+ return false;
+ }
+ }
+
+ // If finding alarming devices issue a different command
+ if (alarm_only)
+ write_byte(_SEARCH_ALARM); // issue the alarming search command
+ else
+ write_byte(_SEARCH); // issue the search command
+
+ // loop to do the search
+ do
+ {
+ // read a bit and its compliment
+ bit_test = ((uint8_t)read_bit()) << 1;
+ bit_test |= ((uint8_t)read_bit());
+
+ // check for no devices on 1-wire
+ if (bit_test == 3)
+ break;
+ else
+ {
+ // all devices coupled have 0 or 1
+ if (bit_test > 0)
+ search_direction = !(bit_test & 0x01); // bit write value for search
+ else
+ {
+ // if this discrepancy if before the Last Discrepancy
+ // on a previous next then pick the same as last time
+ if (bit_number < _last_discrepancy)
+ search_direction = ((_serial[serial_byte_number] & serial_byte_mask) > 0);
+ else
+ // if equal to last pick 1, if not then pick 0
+ search_direction = (bit_number == _last_discrepancy);
+
+ // if 0 was picked then record its position in LastZero
+ if (search_direction == 0)
+ {
+ last_zero = bit_number;
+
+ // check for Last discrepancy in family
+ if (last_zero < 9)
+ _last_family_discrepancy = last_zero;
+ }
+ }
+
+ // set or clear the bit in the SerialNum[portnum] byte serial_byte_number
+ // with mask serial_byte_mask
+ if (search_direction == 1)
+ _serial[serial_byte_number] |= serial_byte_mask;
+ else
+ _serial[serial_byte_number] &= ~serial_byte_mask;
+
+ // serial number search direction write bit
+ write_bit((bool)search_direction);
+
+ // increment the byte counter bit_number
+ // and shift the mask serial_byte_mask
+ bit_number++;
+ serial_byte_mask <<= 1;
+
+ // if the mask is 0 then go to new SerialNum[portnum] byte serial_byte_number
+ // and reset mask
+ if (serial_byte_mask == 0)
+ {
+ // The below has been added to accomidate the valid CRC with the
+ // possible changing serial number values of the DS28E04.
+ if (((_serial[0] & 0x7F) == 0x1C) && (serial_byte_number == 1))
+ _crc_check(0x7F, &lastcrc8);
+ else
+ _crc_check(_serial[serial_byte_number], &lastcrc8); // accumulate the CRC
+
+ serial_byte_number++;
+ serial_byte_mask = 1;
+ }
+ }
+ }
+ while(serial_byte_number < 8); // loop until through all SerialNum[portnum] bytes 0-7
+
+ // if the search was successful then
+ if (!((bit_number < 65) || lastcrc8))
+ {
+ // search successful so set LastDiscrepancy[portnum],LastDevice[portnum],next_result
+ _last_discrepancy = last_zero;
+ _last_device = (_last_discrepancy == 0);
+ next_result = true;
+ }
+ }
+
+ // if no device found then reset counters so next 'next' will be
+ // like a first
+ if (!next_result || !_serial[0])
+ {
+ _last_discrepancy = 0;
+ _last_device = false;
+ _last_family_discrepancy = 0;
+ next_result = false;
+ }
+
+ return next_result;
+}
+
+void OneWire::get_serial_number(uint8_t *sn_buffer, bool do_read)
+{
+ if (do_read)
+ memcpy(sn_buffer, _serial, _SERIAL_LENGTH);
+ else
+ memcpy(_serial, sn_buffer, _SERIAL_LENGTH);
+}
+
+void OneWire::_wait(uint16_t time)
+{
+ _timer->set_autoreload_value(time);
+ _timer->enable_counter();
+
+ while(_timer->get_counter_value() < time);
+
+ _timer->disable_counter();
+ _timer->set_counter_value(0);
+}
+
+void OneWire::_crc_check(uint8_t data, uint8_t *crc_byte)
+{
+ uint8_t tmp = *crc_byte;
+
+ for (uint8_t bit_count = 0; bit_count < 8; bit_count++)
+ {
+ if ((data & 0x01) ^ (tmp & 0x01)) {
+ tmp = tmp >> 1;
+ tmp = tmp ^ 0x8c;//0b10001100;
+ }
+ else {
+ tmp = tmp >> 1;
+ }
+
+ data = data >> 1;
+ }
+
+ *crc_byte = tmp;
+}
+
+} /* namespace extra */
+
+} /* namespace cm3cpp */
diff --git a/extra/one_wire.h b/extra/one_wire.h
new file mode 100644
index 0000000..4fb2d11
--- /dev/null
+++ b/extra/one_wire.h
@@ -0,0 +1,60 @@
+#ifndef EXTRA_ONE_WIRE_H_
+#define EXTRA_ONE_WIRE_H_
+
+#include <string.h>
+#include <libopencm3_cpp_extensions/cm3cpp_gpio.h>
+#include <libopencm3_cpp_extensions/timer_ext.h>
+
+namespace cm3cpp {
+
+namespace extra {
+
+namespace gpio = cm3cpp::gpio;
+namespace timer = cm3cpp::tim;
+
+class OneWire
+{
+public:
+ OneWire(gpio::Pinout p, uint8_t tim_number, uint32_t tim_presc);
+ ~OneWire() = default;
+
+ uint8_t read_byte(void);
+ void write_byte(uint8_t data);
+ bool read_bit(void);
+ void write_bit(bool bit);
+ bool touch_reset(void);
+ bool search_first(bool do_reset, bool alarm_only);
+ bool search_next(bool do_reset, bool alarm_only);
+ void get_serial_number(uint8_t *sn_buffer, bool do_read);
+
+private:
+ static constexpr uint16_t _SLOT_LENGTH = 78;
+ static constexpr uint16_t _RESET_PULSE_TIME_US = 520;
+ static constexpr uint16_t _LOW_PULSE_TIME_US = 3;
+ static constexpr uint16_t _READ_SAMPLE_TIME_US = 12;
+ static constexpr uint16_t _READ_SAMPLE_WAIT_US = (_READ_SAMPLE_TIME_US - _LOW_PULSE_TIME_US);
+ static constexpr uint16_t _END_READ_SLOT_WAIT_US = (_SLOT_LENGTH - _READ_SAMPLE_TIME_US);
+ static constexpr uint16_t _RECOVERY_TIME_US = 6;
+ static constexpr uint16_t _WRITE_SLOT_WAIT_US = (_SLOT_LENGTH - _LOW_PULSE_TIME_US);
+ static constexpr uint8_t _SERIAL_LENGTH = 8;
+
+ static constexpr uint8_t _SEARCH = 0xF0;
+ static constexpr uint8_t _SEARCH_ALARM = 0xEC;
+
+ gpio::Gpio _pinout;
+ tim::Timer *_timer;
+ uint8_t _serial[_SERIAL_LENGTH];
+
+ int8_t _last_discrepancy;
+ int8_t _last_family_discrepancy;
+ bool _last_device;
+
+ void _wait(uint16_t time);
+ void _crc_check(uint8_t data, uint8_t *crc_byte);
+};
+
+} /* namespace extra */
+
+} /* namespace cm3cpp */
+
+#endif /* EXTRA_ONE_WIRE_H_ */
diff --git a/utils/round_buffer.h b/utils/round_buffer.h
index 7221f33..3bf2e07 100644
--- a/utils/round_buffer.h
+++ b/utils/round_buffer.h
@@ -24,8 +24,8 @@
ROUND BUFFER implementation, public interface
*/
-#ifndef ROUND_BUFFER_H
-#define ROUND_BUFFER_H
+#ifndef UTILS_ROUND_BUFFER_H_
+#define UTILS_ROUND_BUFFER_H_
#include <cm3cpp_config.h>
#include <stdint.h>
@@ -267,9 +267,8 @@ private:
}
};
-
} // namespace utils
} // namespace cm3ext
-#endif
+#endif /* UTILS_ROUND_BUFFER_H_ */