Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Revision 4:31695331ce17, committed 2022-01-10
- Comitter:
- marcodesilva
- Date:
- Mon Jan 10 20:38:41 2022 +0000
- Parent:
- 3:7912ab1400c4
- Commit message:
- compila al 10/01/2022, da testare sul tool
Changed in this revision
--- a/RoboClaw.lib Tue Sep 14 12:09:47 2021 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -https://os.mbed.com/users/anfontanelli/code/RoboClaw/#6a4969d25627
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/RoboClaw/RoboClaw.cpp Mon Jan 10 20:38:41 2022 +0000
@@ -0,0 +1,291 @@
+#include "RoboClaw.h"
+#include <stdarg.h>
+
+#define MAXTRY 1
+#define SetDWORDval(arg) (uint8_t)(arg>>24),(uint8_t)(arg>>16),(uint8_t)(arg>>8),(uint8_t)arg
+#define SetWORDval(arg) (uint8_t)(arg>>8),(uint8_t)arg
+
+RoboClaw::RoboClaw(uint8_t adr, int baudrate, PinName rx, PinName tx, double _read_timeout) : _roboclaw(rx, tx){
+ _roboclaw.set_baud(baudrate);//_roboclaw.baud(baudrate);
+
+ rx_in = 0;
+ address = adr;
+ //readTime = 0.0;
+ //readTimer.start();
+ read_timeout = _read_timeout;
+
+}
+
+void RoboClaw::crc_clear(){
+ crc = 0;
+}
+
+
+void RoboClaw::flushSerialBuffer(void) {
+ char char1[1];
+
+ while (_roboclaw.readable()) {
+ _roboclaw.read_timeout(char1,1,read_timeout);
+ }
+return; }
+
+void RoboClaw::crc_update (uint8_t data){
+ int i;
+ crc = crc ^ ((uint16_t)data << 8);
+ for (i=0; i<8; i++) {
+ if (crc & 0x8000)
+ crc = (crc << 1) ^ 0x1021;
+ else
+ crc <<= 1;
+ }
+}
+
+uint16_t RoboClaw::crc_get(){
+ return crc;
+}
+
+uint16_t RoboClaw::crc16(uint8_t *packet, int nBytes){
+ uint16_t crc_;
+ for (int byte = 0; byte < nBytes; byte++) {
+ crc_ = crc_ ^ ((uint16_t)packet[byte] << 8);
+ for (uint8_t bit = 0; bit < 8; bit++) {
+ if (crc_ & 0x8000) {
+ crc_ = (crc_ << 1) ^ 0x1021;
+ } else {
+ crc_ = crc_ << 1;
+ }
+ }
+ }
+ return crc_;
+}
+
+void RoboClaw::write_n(uint8_t cnt, ... ){
+ uint8_t count = 0;
+ char dat[1];
+ char r_dat[1];
+ r_dat[0] = ' ';
+ char crc_[2];
+ do {
+ _roboclaw.flush();
+
+ crc_clear();
+ va_list marker;
+ va_start( marker, cnt );
+ for(uint8_t index=0; index<cnt; index++) {
+ uint8_t data = va_arg(marker, unsigned int);
+ dat[0] = data;
+ crc_update(data);
+ _roboclaw.write(dat,1);
+ }
+ va_end( marker );
+ uint16_t crc = crc_get();
+ crc_[0]=crc>>8;
+ crc_[1]=crc;
+ _roboclaw.write(crc_,2);
+ _roboclaw.read_timeout(r_dat,1,read_timeout);
+
+ count ++;
+
+ }while((uint16_t)r_dat[0] != 0xFF&& count <=MAXTRY);
+
+}
+
+void RoboClaw::write_(uint8_t command, uint8_t data, bool reading, bool crcon){
+ // _roboclaw.putc(address);
+ // _roboclaw.putc(command);
+
+ if(reading == false) {
+ if(crcon == true) {
+ uint8_t packet[2] = {address, command};
+ uint16_t checksum = crc16(packet,2);
+ // _roboclaw.putc(checksum>>8);
+ // _roboclaw.putc(checksum);
+ } else {
+ uint8_t packet[3] = {address, command, data};
+ uint16_t checksum = crc16(packet,3);
+ // _roboclaw.putc(data);
+ // _roboclaw.putc(checksum>>8);
+ // _roboclaw.putc(checksum);
+ }
+ }
+}
+
+bool RoboClaw::read_n(uint8_t address, uint8_t cmd, int n_byte, int32_t &value){
+ uint16_t read_byte[n_byte];
+ uint16_t received_crc;
+ int dataRead=0;
+ char tx_buffer[2];
+
+ tx_buffer[0] = address;
+ tx_buffer[1] = cmd;
+
+ rx_in = 0;
+ crc_clear();
+
+ _roboclaw.flush();
+ _roboclaw.write(tx_buffer,2);
+
+ crc_update(address);
+ crc_update(cmd);
+
+ dataRead = _roboclaw.read_timeout(rx_buffer,7,read_timeout);
+ //printf("d: %d\r\n", dataRead);
+ //printf("add: %x, cmd: %x, 0: %x, 1: %x, 2: %x, 3: %x, 4: %x, 5: %x, 6: %x \r\n",(uint16_t)tx_buffer[0],(uint16_t)tx_buffer[1],(uint16_t)rx_buffer[0],(uint16_t)rx_buffer[1],(uint16_t)rx_buffer[2],(uint16_t)rx_buffer[3],(uint16_t)rx_buffer[4],(uint16_t)rx_buffer[5],(uint16_t)rx_buffer[6]);
+ //printf("dopo del read\r\n");
+ for(int i = 0; i<=n_byte-3; i++){
+ crc_update((uint16_t)rx_buffer[i]);
+ }
+
+ received_crc = (uint16_t)rx_buffer[n_byte-2]<<8;
+ received_crc |= (uint16_t)rx_buffer[n_byte-1];
+
+ if(received_crc == crc_get()){
+ value = (uint16_t)rx_buffer[0]<<24;
+ value |= (uint16_t)rx_buffer[1]<<16;
+ value |= (uint16_t)rx_buffer[2]<<8;
+ value |= (uint16_t)rx_buffer[3];
+ return true;
+ }else{
+ //printf("crc: %x \r\n", crc_get());
+ //printf("received crc: %x \r\n", received_crc);
+ printf("err \r\n");
+
+
+ return false;
+ }
+}
+
+
+void RoboClaw::ForwardM1(int speed){
+ write_(M1FORWARD,speed,false,false);
+}
+
+void RoboClaw::BackwardM1(int speed){
+ write_(M1BACKWARD,speed,false,false);
+}
+
+void RoboClaw::ForwardM2(int speed){
+ write_(M2FORWARD,speed,false,false);
+}
+
+void RoboClaw::BackwardM2(int speed){
+ write_(M2BACKWARD,speed,false,false);
+}
+
+void RoboClaw::Forward(int speed){
+ write_(MIXEDFORWARD,speed,false,false);
+}
+
+void RoboClaw::Backward(int speed){
+ write_(MIXEDBACKWARD,speed,false,false);
+}
+
+void RoboClaw::ReadFirm(){
+ write_(GETVERSION,0x00,true,false);
+}
+
+bool RoboClaw::ReadEncM1(int32_t &encPulse){
+ int32_t value=0;
+ if (read_n(address, GETM1ENC, 7, value) == true){
+ encPulse = value;
+ return true;
+ }else{
+ return false;
+ }
+}
+
+bool RoboClaw::ReadEncM2(int32_t &encPulse){
+ int32_t value=0;
+ if (read_n(address, GETM2ENC, 7, value) == true){
+ encPulse = value;
+ return true;
+ }else{
+ return false;
+ }
+}
+
+bool RoboClaw::ReadSpeedM1(int32_t &speed){
+ int32_t value=0;
+ if (read_n(address, GETM1SPEED, 7, value) == true){
+ speed = value;
+ return true;
+ }else{
+ return false;
+ }
+}
+
+bool RoboClaw::ReadSpeedM2(int32_t &speed){
+ int32_t value=0;
+ if (read_n(address, GETM2SPEED, 7, value) == true){
+ speed = value;
+ return true;
+ }else{
+ return false;
+ }
+}
+
+
+bool RoboClaw::ReadCurrentM1M2(int32_t& currentM1, int32_t& currentM2){
+ int32_t value=0;
+ if (read_n(address, GETCURRENTS, 6, value) == true){
+ currentM1 = value>>16;
+ currentM2 = value&0xFFFF;
+ return true;
+ }else{
+ return false;
+ }
+
+}
+
+void RoboClaw::ResetEnc(){
+ write_n(2,address,RESETENC);
+}
+
+void RoboClaw::SpeedM1(int32_t speed){
+ write_n(6,address,M1SPEED,SetDWORDval(speed));
+}
+
+void RoboClaw::SpeedM2(int32_t speed){
+ write_n(6,address,M2SPEED,SetDWORDval(speed));
+}
+
+void RoboClaw::SpeedAccelM1(int32_t accel, int32_t speed){
+ write_n(10,address,M1SPEEDACCEL,SetDWORDval(accel),SetDWORDval(speed));
+}
+
+void RoboClaw::SpeedAccelM2(int32_t accel, int32_t speed){
+ write_n(10,address,M2SPEEDACCEL,SetDWORDval(accel),SetDWORDval(speed));
+}
+
+void RoboClaw::SpeedAccelM1M2(int32_t accel, int32_t speed1, int32_t speed2){
+ write_n(14,address,MIXEDSPEEDACCEL,SetDWORDval(accel),SetDWORDval(speed1),SetDWORDval(speed2));
+}
+
+void RoboClaw::SpeedDistanceM1(int32_t speed, uint32_t distance, uint8_t buffer){
+ write_n(11,address,M1SPEEDDIST,SetDWORDval(speed),SetDWORDval(distance),buffer);
+}
+
+void RoboClaw::SpeedDistanceM2(int32_t speed, uint32_t distance, uint8_t buffer){
+ write_n(11,address,M2SPEEDDIST,SetDWORDval(speed),SetDWORDval(distance),buffer);
+}
+
+void RoboClaw::SpeedAccelDistanceM1(int32_t accel, int32_t speed, uint32_t distance, uint8_t buffer){
+ write_n(15,address,M1SPEEDACCELDIST,SetDWORDval(accel),SetDWORDval(speed),SetDWORDval(distance),buffer);
+}
+
+void RoboClaw::SpeedAccelDistanceM2(int32_t accel, int32_t speed, uint32_t distance, uint8_t buffer){
+ write_n(15,address,M2SPEEDACCELDIST,SetDWORDval(accel),SetDWORDval(speed),SetDWORDval(distance),buffer);
+}
+
+void RoboClaw::SpeedAccelDeccelPositionM1(uint32_t accel, int32_t speed, uint32_t deccel, int32_t position, uint8_t flag){
+ write_n(19,address,M1SPEEDACCELDECCELPOS,SetDWORDval(accel),SetDWORDval(speed),SetDWORDval(deccel),SetDWORDval(position),flag);
+}
+
+void RoboClaw::SpeedAccelDeccelPositionM2(uint32_t accel, int32_t speed, uint32_t deccel, int32_t position, uint8_t flag){
+ write_n(19,address,M2SPEEDACCELDECCELPOS,SetDWORDval(accel),SetDWORDval(speed),SetDWORDval(deccel),SetDWORDval(position),flag);
+}
+
+void RoboClaw::SpeedAccelDeccelPositionM1M2(uint32_t accel1,uint32_t speed1,uint32_t deccel1, int32_t position1,uint32_t accel2,uint32_t speed2,uint32_t deccel2, int32_t position2,uint8_t flag){
+ write_n(35,address,MIXEDSPEEDACCELDECCELPOS,SetDWORDval(accel1),SetDWORDval(speed1),SetDWORDval(deccel1),SetDWORDval(position1),SetDWORDval(accel2),SetDWORDval(speed2),SetDWORDval(deccel2),SetDWORDval(position2),flag);
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/RoboClaw/RoboClaw.h Mon Jan 10 20:38:41 2022 +0000
@@ -0,0 +1,121 @@
+#ifndef ROBOCLAW_H
+#define ROBOCLAW_H
+#include "mbed.h"
+#include "registers.h"
+#include "UARTSerial_mio.h"
+/** The RoboClaw class, yo ucan use the library with : http://www.ionmc.com/RoboClaw-2x15A-Motor-Controller_p_10.html
+* Used to control one or two motors with (or not) encoders
+* @code
+* #include "mbed.h"
+* #include "RoboClaw.h"
+*
+* RoboClaw roboclaw(115200, PA_11, PA_12);
+*
+* int main() {
+* roboclaw.ForwardM1(ADR, 127);
+* while(1);
+* }
+* @endcode
+*/
+
+class RoboClaw
+{
+public:
+ /** Create RoboClaw instance
+ */
+ RoboClaw(uint8_t adr, int baudrate, PinName rx, PinName tx, double _read_timeout);
+
+ /** Forward and Backward functions
+ * @param address address of the device
+ * @param speed speed of the motor (between 0 and 127)
+ * @note Forward and Backward functions
+ */
+ void ForwardM1(int speed);
+ void BackwardM1(int speed);
+ void ForwardM2(int speed);
+ void BackwardM2(int speed);
+
+ /** Forward and Backward functions
+ * @param address address of the device
+ * @param speed speed of the motor (between 0 and 127)
+ * @note Forward and Backward functions, it turns the two motors
+ */
+ void Forward(int speed);
+ void Backward(int speed);
+
+ /** Read the Firmware
+ * @param address address of the device
+ */
+ void ReadFirm();
+
+ /** Read encoder and speed of M1 or M2
+ * @param address address of the device
+ * @note Read encoder in ticks
+ * @note Read speed in ticks per second
+ */
+ bool ReadEncM1(int32_t &encPulse);
+ bool ReadEncM2(int32_t &encPulse);
+ bool ReadSpeedM1(int32_t &speed);
+ bool ReadSpeedM2(int32_t &speed);
+ bool ReadCurrentM1M2(int32_t ¤tM1, int32_t ¤tM2);
+
+
+ /** Set both encoders to zero
+ * @param address address of the device
+ */
+ void ResetEnc();
+
+ /** Set speed of Motor with different parameter (only in ticks)
+ * @param address address of the device
+ * @note Set the Speed
+ * @note Set the Speed and Accel
+ * @note Set the Speed and Distance
+ * @note Set the Speed, Accel and Distance
+ * @note Set the Speed, Accel, Decceleration and Position
+ */
+ void SpeedM1(int32_t speed);
+ void SpeedM2(int32_t speed);
+ void SpeedAccelM1(int32_t accel, int32_t speed);
+ void SpeedAccelM2(int32_t accel, int32_t speed);
+ void SpeedAccelM1M2(int32_t accel, int32_t speed1, int32_t speed2);
+ void SpeedDistanceM1(int32_t speed, uint32_t distance, uint8_t buffer);
+ void SpeedDistanceM2(int32_t speed, uint32_t distance, uint8_t buffer);
+ void SpeedAccelDistanceM1(int32_t accel, int32_t speed, uint32_t distance, uint8_t buffer);
+ void SpeedAccelDistanceM2(int32_t accel, int32_t speed, uint32_t distance, uint8_t buffer);
+ void SpeedAccelDeccelPositionM1(uint32_t accel, int32_t speed, uint32_t deccel, int32_t position, uint8_t flag);
+ void SpeedAccelDeccelPositionM2(uint32_t accel, int32_t speed, uint32_t deccel, int32_t position, uint8_t flag);
+ void SpeedAccelDeccelPositionM1M2(uint32_t accel1,uint32_t speed1,uint32_t deccel1, int32_t position1,uint32_t accel2,uint32_t speed2,uint32_t deccel2, int32_t position2,uint8_t flag);
+
+private:
+ UARTSerial_mio _roboclaw;
+ uint16_t crc;
+ uint8_t address;
+ void crc_clear();
+ void crc_update(uint8_t data);
+ uint16_t crc_get();
+
+ void write_n(uint8_t cnt, ...);
+ void write_(uint8_t command, uint8_t data, bool reading, bool crcon);
+
+ uint16_t crc16(uint8_t *packet, int nBytes);
+ int16_t read_(void);
+ bool read_n(uint8_t address, uint8_t cmd, int n_byte, int32_t &value);
+ void flushSerialBuffer(void);
+ void Rx_interrupt();
+ // Circular buffers for serial TX and RX data - used by interrupt routines
+ const int buffer_size = 7;
+ // might need to increase buffer size for high baud rates
+ char rx_buffer[7];
+ // Circular buffer pointers
+ // volatile makes read-modify-write atomic
+ //Timer readTimer;
+ //double readTime;
+ //double readTimePrec;
+ volatile int rx_in;
+ double read_timeout;
+ // Line buffers for sprintf and sscanf
+
+ char rx_line[80];
+};
+
+#endif
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/RoboClaw/UARTserial_mio/UARTSerial_mio.cpp Mon Jan 10 20:38:41 2022 +0000
@@ -0,0 +1,482 @@
+/* mbed Microcontroller Library
+ * Copyright (c) 2006-2017 ARM Limited
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "UARTSerial_mio.h"
+
+#if (DEVICE_SERIAL && DEVICE_INTERRUPTIN)
+
+#include "platform/mbed_poll.h"
+
+#if MBED_CONF_RTOS_PRESENT
+#include "rtos/ThisThread.h"
+#else
+#include "platform/mbed_wait_api.h"
+#endif
+
+namespace mbed {
+
+UARTSerial_mio::UARTSerial_mio(PinName tx, PinName rx, int baud) :
+ SerialBase(tx, rx, baud),
+ _blocking(true),
+ _tx_irq_enabled(false),
+ _rx_irq_enabled(false),
+ _tx_enabled(true),
+ _rx_enabled(true),
+ _dcd_irq(NULL)
+{
+ /* Attatch IRQ routines to the serial device. */
+ enable_rx_irq();
+}
+
+UARTSerial_mio::~UARTSerial_mio()
+{
+ delete _dcd_irq;
+}
+
+void UARTSerial_mio::dcd_irq()
+{
+ wake();
+}
+
+void UARTSerial_mio::set_baud(int baud)
+{
+ SerialBase::baud(baud);
+}
+
+void UARTSerial_mio::set_format(int bits, Parity parity, int stop_bits)
+{
+ api_lock();
+ SerialBase::format(bits, parity, stop_bits);
+ api_unlock();
+}
+
+#if DEVICE_SERIAL_FC
+void UARTSerial_mio::set_flow_control(Flow type, PinName flow1, PinName flow2)
+{
+ api_lock();
+ SerialBase::set_flow_control(type, flow1, flow2);
+ api_unlock();
+}
+#endif
+
+int UARTSerial_mio::close(){return 0;}
+
+int UARTSerial_mio::isatty(){return 1;}
+
+
+off_t UARTSerial_mio::seek(off_t offset, int whence)
+{
+ /*XXX lseek can be done theoratically, but is it sane to mark positions on a dynamically growing/shrinking
+ * buffer system (from an interrupt context) */
+ return -ESPIPE;
+}
+
+int UARTSerial_mio::sync()
+{
+ api_lock();
+ while (!_txbuf.empty()) {
+ api_unlock();
+ // Doing better than wait would require TxIRQ to also do wake() when becoming empty. Worth it?
+ wait_us(500);
+ api_lock();
+ }
+
+ api_unlock();
+
+ return 0;
+}
+
+int UARTSerial_mio::flush()
+{
+ api_lock();
+ char c;
+
+ while (!_rxbuf.empty()) {
+ api_unlock();
+ // Doing better than wait would require TxIRQ to also do wake() when becoming empty. Worth it?
+ wait_us(500);
+ _rxbuf.pop(c);
+ api_lock();
+ }
+
+ api_unlock();
+
+ return 0;
+}
+
+void UARTSerial_mio::sigio(Callback<void()> func)
+{
+ core_util_critical_section_enter();
+ _sigio_cb = func;
+ if (_sigio_cb) {
+ short current_events = poll(0x7FFF);
+ if (current_events) {
+ _sigio_cb();
+ }
+ }
+ core_util_critical_section_exit();
+}
+
+/* Special synchronous write designed to work from critical section, such
+ * as in mbed_error_vprintf.
+ */
+ssize_t UARTSerial_mio::write_unbuffered(const char *buf_ptr, size_t length)
+{
+ while (!_txbuf.empty()) {
+ tx_irq();
+ }
+
+ for (size_t data_written = 0; data_written < length; data_written++) {
+ SerialBase::_base_putc(*buf_ptr++);
+ }
+
+ return length;
+}
+
+ssize_t UARTSerial_mio::write(const void *buffer, size_t length)
+{
+ size_t data_written = 0;
+ const char *buf_ptr = static_cast<const char *>(buffer);
+
+ if (length == 0) {
+ return 0;
+ }
+
+ if (core_util_in_critical_section()) {
+ return write_unbuffered(buf_ptr, length);
+ }
+
+ api_lock();
+
+ // Unlike read, we should write the whole thing if blocking. POSIX only
+ // allows partial as a side-effect of signal handling; it normally tries to
+ // write everything if blocking. Without signals we can always write all.
+ while (data_written < length) {
+
+ if (_txbuf.full()) {
+ if (!_blocking) {
+ break;
+ }
+ do {
+ api_unlock();
+ wait_ms(1); // XXX todo - proper wait, WFE for non-rtos ?
+ api_lock();
+ } while (_txbuf.full());
+ }
+
+ while (data_written < length && !_txbuf.full()) {
+ _txbuf.push(*buf_ptr++);
+ data_written++;
+ }
+
+ core_util_critical_section_enter();
+ if (_tx_enabled && !_tx_irq_enabled) {
+ UARTSerial_mio::tx_irq(); // only write to hardware in one place
+ if (!_txbuf.empty()) {
+ enable_tx_irq();
+ }
+ }
+ core_util_critical_section_exit();
+ }
+
+ api_unlock();
+
+ return data_written != 0 ? (ssize_t) data_written : (ssize_t) - EAGAIN;
+}
+
+ssize_t UARTSerial_mio::read(void *buffer, size_t length)
+{
+ size_t data_read = 0;
+
+ float timeout = 1.0; //ms
+ float tm = 0.0;
+
+ char *ptr = static_cast<char *>(buffer);
+
+ if (length == 0) {
+ return 0;
+ }
+
+ api_lock();
+
+ while (_rxbuf.size()!=length && tm <= timeout) {
+ if (!_blocking) {
+ api_unlock();
+ return -EAGAIN;
+ }
+ api_unlock();
+ wait_us(10); // XXX todo - proper wait, WFE for non-rtos ?
+ api_lock();
+ tm = tm + 0.01; //10/1000
+ }
+
+ while (data_read < length && !_rxbuf.empty()) {
+ _rxbuf.pop(*ptr++);
+ data_read++;
+ }
+
+ core_util_critical_section_enter();
+ if (_rx_enabled && !_rx_irq_enabled) {
+ UARTSerial_mio::rx_irq(); // only read from hardware in one place
+ if (!_rxbuf.full()) {
+ enable_rx_irq();
+ }
+ }
+ core_util_critical_section_exit();
+
+ api_unlock();
+
+ return data_read;
+}
+
+ssize_t UARTSerial_mio::read_timeout(void *buffer, size_t length, double _timeOut)
+{
+ size_t data_read = 0;
+
+ double timeout = _timeOut; //ms
+ double tm = 0.0;
+
+ char *ptr = static_cast<char *>(buffer);
+
+ if (length == 0) {
+ return 0;
+ }
+
+ api_lock();
+
+ while (_rxbuf.size()!=length && tm<=timeout) {
+ if (!_blocking) {
+ api_unlock();
+ return -EAGAIN;
+ }
+ api_unlock();
+ wait_us(1); // XXX todo - proper wait, WFE for non-rtos ?
+ api_lock();
+ tm = tm + 0.001; //10/1000
+
+ }
+
+ //printf("tm: %f\r\n",tm);
+ tm = 0.0;
+ while (data_read < length && !_rxbuf.empty() && tm<=timeout) {
+ _rxbuf.pop(*ptr++);
+ data_read++;
+ tm = tm + 0.001; //10/1000
+ }
+
+ core_util_critical_section_enter();
+ if (_rx_enabled && !_rx_irq_enabled) {
+ UARTSerial_mio::rx_irq(); // only read from hardware in one place
+ if (!_rxbuf.full()) {
+ enable_rx_irq();
+ }
+ }
+ core_util_critical_section_exit();
+
+ api_unlock();
+
+ return data_read;
+}
+
+bool UARTSerial_mio::hup() const
+{
+ return _dcd_irq && _dcd_irq->read() != 0;
+}
+
+void UARTSerial_mio::wake()
+{
+ if (_sigio_cb) {
+ _sigio_cb();
+ }
+}
+
+short UARTSerial_mio::poll(short events) const
+{
+
+ short revents = 0;
+ /* Check the Circular Buffer if space available for writing out */
+
+
+ if (!_rxbuf.empty()) {
+ revents |= POLLIN;
+ }
+
+ /* POLLHUP and POLLOUT are mutually exclusive */
+ if (hup()) {
+ revents |= POLLHUP;
+ } else if (!_txbuf.full()) {
+ revents |= POLLOUT;
+ }
+
+ /*TODO Handle other event types */
+
+ return revents;
+}
+
+void UARTSerial_mio::lock()
+{
+ // This is the override for SerialBase.
+ // No lock required as we only use SerialBase from interrupt or from
+ // inside our own critical section.
+}
+
+void UARTSerial_mio::unlock()
+{
+ // This is the override for SerialBase.
+}
+
+void UARTSerial_mio::api_lock(void)
+{
+ //_mutex.lock();
+}
+
+void UARTSerial_mio::api_unlock(void)
+{
+ //_mutex.unlock();
+}
+
+void UARTSerial_mio::rx_irq(void)
+{
+ bool was_empty = _rxbuf.empty();
+
+ /* Fill in the receive buffer if the peripheral is readable
+ * and receive buffer is not full. */
+ while (!_rxbuf.full() && SerialBase::readable()) {
+ char data = SerialBase::_base_getc();
+ _rxbuf.push(data);
+ }
+
+ if (_rx_irq_enabled && _rxbuf.full()) {
+ disable_rx_irq();
+ }
+
+ /* Report the File handler that data is ready to be read from the buffer. */
+ if (was_empty && !_rxbuf.empty()) {
+ wake();
+ }
+}
+
+// Also called from write to start transfer
+void UARTSerial_mio::tx_irq(void)
+{
+ bool was_full = _txbuf.full();
+ char data;
+
+ /* Write to the peripheral if there is something to write
+ * and if the peripheral is available to write. */
+ while (SerialBase::writeable() && _txbuf.pop(data)) {
+ SerialBase::_base_putc(data);
+ }
+
+ if (_tx_irq_enabled && _txbuf.empty()) {
+ disable_tx_irq();
+ }
+
+ /* Report the File handler that data can be written to peripheral. */
+ if (was_full && !_txbuf.full() && !hup()) {
+ wake();
+ }
+}
+
+/* These are all called from critical section */
+void UARTSerial_mio::enable_rx_irq()
+{
+ SerialBase::attach(callback(this, &UARTSerial_mio::rx_irq), RxIrq);
+ _rx_irq_enabled = true;
+}
+
+void UARTSerial_mio::disable_rx_irq()
+{
+ SerialBase::attach(NULL, RxIrq);
+ _rx_irq_enabled = false;
+}
+
+void UARTSerial_mio::enable_tx_irq()
+{
+ SerialBase::attach(callback(this, &UARTSerial_mio::tx_irq), TxIrq);
+ _tx_irq_enabled = true;
+}
+
+void UARTSerial_mio::disable_tx_irq()
+{
+ SerialBase::attach(NULL, TxIrq);
+ _tx_irq_enabled = false;
+}
+
+int UARTSerial_mio::enable_input(bool enabled)
+{
+ core_util_critical_section_enter();
+ if (_rx_enabled != enabled) {
+ if (enabled) {
+ UARTSerial_mio::rx_irq();
+ if (!_rxbuf.full()) {
+ enable_rx_irq();
+ }
+ } else {
+ disable_rx_irq();
+ }
+ _rx_enabled = enabled;
+ }
+ core_util_critical_section_exit();
+
+ return 0;
+}
+
+int UARTSerial_mio::enable_output(bool enabled)
+{
+ core_util_critical_section_enter();
+ if (_tx_enabled != enabled) {
+ if (enabled) {
+ UARTSerial_mio::tx_irq();
+ if (!_txbuf.empty()) {
+ enable_tx_irq();
+ }
+ } else {
+ disable_tx_irq();
+ }
+ _tx_enabled = enabled;
+ }
+ core_util_critical_section_exit();
+
+ return 0;
+}
+
+void UARTSerial_mio::wait_ms(uint32_t millisec)
+{
+ /* wait_ms implementation for RTOS spins until exact microseconds - we
+ * want to just sleep until next tick.
+ */
+#if MBED_CONF_RTOS_PRESENT
+ rtos::ThisThread::sleep_for(millisec);
+#else
+ ::wait_ms(millisec);
+#endif
+}
+
+void UARTSerial_mio::wait_us(uint32_t microseconds)
+{
+ /* wait_ms implementation for RTOS spins until exact microseconds - we
+ * want to just sleep until next tick.
+ */
+#if MBED_CONF_RTOS_PRESENT
+ rtos::ThisThread::sleep_for(microseconds/1000);
+#else
+ ::wait_us(microseconds);
+#endif
+}
+} //namespace mbed
+
+#endif //(DEVICE_SERIAL && DEVICE_INTERRUPTIN)
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/RoboClaw/UARTserial_mio/UARTSerial_mio.h Mon Jan 10 20:38:41 2022 +0000
@@ -0,0 +1,308 @@
+
+#ifndef MBED_UARTSERIAL_MIO_H
+#define MBED_UARTSERIAL_MIO_H
+
+#include "platform/platform.h"
+
+#if (DEVICE_SERIAL && DEVICE_INTERRUPTIN) || defined(DOXYGEN_ONLY)
+
+#include "platform/FileHandle.h"
+#include "SerialBase.h"
+#include "InterruptIn.h"
+#include "platform/PlatformMutex.h"
+#include "hal/serial_api.h"
+#include "platform/CircularBuffer.h"
+#include "platform/NonCopyable.h"
+
+#include "mbed.h"
+
+#ifndef MBED_CONF_DRIVERS_UART_SERIAL_RXBUF_SIZE
+#define MBED_CONF_DRIVERS_UART_SERIAL_RXBUF_SIZE 256
+#endif
+
+#ifndef MBED_CONF_DRIVERS_UART_SERIAL_TXBUF_SIZE
+#define MBED_CONF_DRIVERS_UART_SERIAL_TXBUF_SIZE 256
+#endif
+
+namespace mbed {
+
+/** \addtogroup drivers */
+
+/** Class providing buffered UART communication functionality using separate circular buffer for send and receive channels
+ *
+ * @ingroup drivers
+ */
+
+class UARTSerial_mio : private SerialBase, public FileHandle, private NonCopyable<UARTSerial_mio> {
+
+public:
+
+ /** Create a UARTSerial_mio port, connected to the specified transmit and receive pins, with a particular baud rate.
+ * @param tx Transmit pin
+ * @param rx Receive pin
+ * @param baud The baud rate of the serial port (optional, defaults to MBED_CONF_PLATFORM_DEFAULT_SERIAL_BAUD_RATE)
+ */
+ UARTSerial_mio(PinName tx, PinName rx, int baud = MBED_CONF_PLATFORM_DEFAULT_SERIAL_BAUD_RATE);
+ virtual ~UARTSerial_mio();
+
+ /** Equivalent to POSIX poll(). Derived from FileHandle.
+ * Provides a mechanism to multiplex input/output over a set of file handles.
+ */
+ virtual short poll(short events) const;
+
+ /* Resolve ambiguities versus our private SerialBase
+ * (for writable, spelling differs, but just in case)
+ */
+ using FileHandle::readable;
+ using FileHandle::writable;
+
+ /** Write the contents of a buffer to a file
+ *
+ * Follows POSIX semantics:
+ *
+ * * if blocking, block until all data is written
+ * * if no data can be written, and non-blocking set, return -EAGAIN
+ * * if some data can be written, and non-blocking set, write partial
+ *
+ * @param buffer The buffer to write from
+ * @param length The number of bytes to write
+ * @return The number of bytes written, negative error on failure
+ */
+ virtual ssize_t write(const void *buffer, size_t length);
+
+ /** Read the contents of a file into a buffer
+ *
+ * Follows POSIX semantics:
+ *
+ * * if no data is available, and non-blocking set return -EAGAIN
+ * * if no data is available, and blocking set, wait until data is available
+ * * If any data is available, call returns immediately
+ *
+ * @param buffer The buffer to read in to
+ * @param length The number of bytes to read
+ * @return The number of bytes read, 0 at end of file, negative error on failure
+ */
+ virtual ssize_t read(void *buffer, size_t length);
+ virtual ssize_t read_timeout(void *buffer, size_t length, double _timeOut);
+
+ /** Close a file
+ *
+ * @return 0 on success, negative error code on failure
+ */
+ virtual int close();
+
+ /** Check if the file in an interactive terminal device
+ *
+ * @return True if the file is a terminal
+ * @return False if the file is not a terminal
+ * @return Negative error code on failure
+ */
+ virtual int isatty();
+
+ /** Move the file position to a given offset from from a given location
+ *
+ * Not valid for a device type FileHandle like UARTSerial_mio.
+ * In case of UARTSerial_mio, returns ESPIPE
+ *
+ * @param offset The offset from whence to move to
+ * @param whence The start of where to seek
+ * SEEK_SET to start from beginning of file,
+ * SEEK_CUR to start from current position in file,
+ * SEEK_END to start from end of file
+ * @return The new offset of the file, negative error code on failure
+ */
+ virtual off_t seek(off_t offset, int whence);
+
+ /** Flush any buffers associated with the file
+ *
+ * @return 0 on success, negative error code on failure
+ */
+ virtual int sync();
+ virtual int flush();
+ /** Set blocking or non-blocking mode
+ * The default is blocking.
+ *
+ * @param blocking true for blocking mode, false for non-blocking mode.
+ */
+ virtual int set_blocking(bool blocking)
+ {
+ _blocking = blocking;
+ return 0;
+ }
+
+ /** Check current blocking or non-blocking mode for file operations.
+ *
+ * @return true for blocking mode, false for non-blocking mode.
+ */
+ virtual bool is_blocking() const
+ {
+ return _blocking;
+ }
+
+ /** Enable or disable input
+ *
+ * Control enabling of device for input. This is primarily intended
+ * for temporary power-saving; the overall ability of the device to operate for
+ * input and/or output may be fixed at creation time, but this call can
+ * allow input to be temporarily disabled to permit power saving without
+ * losing device state.
+ *
+ * @param enabled true to enable input, false to disable.
+ *
+ * @return 0 on success
+ * @return Negative error code on failure
+ */
+ virtual int enable_input(bool enabled);
+
+ /** Enable or disable output
+ *
+ * Control enabling of device for output. This is primarily intended
+ * for temporary power-saving; the overall ability of the device to operate for
+ * input and/or output may be fixed at creation time, but this call can
+ * allow output to be temporarily disabled to permit power saving without
+ * losing device state.
+ *
+ * @param enabled true to enable output, false to disable.
+ *
+ * @return 0 on success
+ * @return Negative error code on failure
+ */
+ virtual int enable_output(bool enabled);
+
+ /** Register a callback on state change of the file.
+ *
+ * The specified callback will be called on state changes such as when
+ * the file can be written to or read from.
+ *
+ * The callback may be called in an interrupt context and should not
+ * perform expensive operations.
+ *
+ * Note! This is not intended as an attach-like asynchronous api, but rather
+ * as a building block for constructing such functionality.
+ *
+ * The exact timing of when the registered function
+ * is called is not guaranteed and susceptible to change. It should be used
+ * as a cue to make read/write/poll calls to find the current state.
+ *
+ * @param func Function to call on state change
+ */
+ virtual void sigio(Callback<void()> func);
+
+ /** Setup interrupt handler for DCD line
+ *
+ * If DCD line is connected, an IRQ handler will be setup.
+ * Does nothing if DCD is NC, i.e., not connected.
+ *
+ * @param dcd_pin Pin-name for DCD
+ * @param active_high a boolean set to true if DCD polarity is active low
+ */
+ void set_data_carrier_detect(PinName dcd_pin, bool active_high = false);
+
+ /** Set the baud rate
+ *
+ * @param baud The baud rate
+ */
+ void set_baud(int baud);
+
+ // Expose private SerialBase::Parity as UARTSerial_mio::Parity
+ using SerialBase::Parity;
+ // In C++11, we wouldn't need to also have using directives for each value
+ using SerialBase::None;
+ using SerialBase::Odd;
+ using SerialBase::Even;
+ using SerialBase::Forced1;
+ using SerialBase::Forced0;
+
+ /** Set the transmission format used by the serial port
+ *
+ * @param bits The number of bits in a word (5-8; default = 8)
+ * @param parity The parity used (None, Odd, Even, Forced1, Forced0; default = None)
+ * @param stop_bits The number of stop bits (1 or 2; default = 1)
+ */
+ void set_format(int bits = 8, Parity parity = UARTSerial_mio::None, int stop_bits = 1);
+
+#if DEVICE_SERIAL_FC
+ // For now use the base enum - but in future we may have extra options
+ // such as XON/XOFF or manual GPIO RTSCTS.
+ using SerialBase::Flow;
+ // In C++11, we wouldn't need to also have using directives for each value
+ using SerialBase::Disabled;
+ using SerialBase::RTS;
+ using SerialBase::CTS;
+ using SerialBase::RTSCTS;
+
+ /** Set the flow control type on the serial port
+ *
+ * @param type the flow control type (Disabled, RTS, CTS, RTSCTS)
+ * @param flow1 the first flow control pin (RTS for RTS or RTSCTS, CTS for CTS)
+ * @param flow2 the second flow control pin (CTS for RTSCTS)
+ */
+ void set_flow_control(Flow type, PinName flow1 = NC, PinName flow2 = NC);
+#endif
+
+private:
+
+ void wait_ms(uint32_t millisec);
+ void wait_us(uint32_t microsec);
+
+ /** SerialBase lock override */
+ virtual void lock(void);
+
+ /** SerialBase unlock override */
+ virtual void unlock(void);
+
+ /** Acquire mutex */
+ virtual void api_lock(void);
+
+ /** Release mutex */
+ virtual void api_unlock(void);
+
+ /** Unbuffered write - invoked when write called from critical section */
+ ssize_t write_unbuffered(const char *buf_ptr, size_t length);
+
+ void enable_rx_irq();
+ void disable_rx_irq();
+ void enable_tx_irq();
+ void disable_tx_irq();
+
+ /** Software serial buffers
+ * By default buffer size is 256 for TX and 256 for RX. Configurable through mbed_app.json
+ */
+ CircularBuffer<char, MBED_CONF_DRIVERS_UART_SERIAL_RXBUF_SIZE> _rxbuf;
+ CircularBuffer<char, MBED_CONF_DRIVERS_UART_SERIAL_TXBUF_SIZE> _txbuf;
+
+ PlatformMutex _mutex;
+
+ Callback<void()> _sigio_cb;
+
+ bool _blocking;
+ bool _tx_irq_enabled;
+ bool _rx_irq_enabled;
+ bool _tx_enabled;
+ bool _rx_enabled;
+ InterruptIn *_dcd_irq;
+
+ /** Device Hanged up
+ * Determines if the device hanged up on us.
+ *
+ * @return True, if hanged up
+ */
+ bool hup() const;
+
+ /** ISRs for serial
+ * Routines to handle interrupts on serial pins.
+ * Copies data into Circular Buffer.
+ * Reports the state change to File handle.
+ */
+ void tx_irq(void);
+ void rx_irq(void);
+
+ void wake(void);
+
+ void dcd_irq(void);
+
+};
+} //namespace mbed
+
+#endif //(DEVICE_SERIAL && DEVICE_INTERRUPTIN) || defined(DOXYGEN_ONLY)
+#endif //MBED_UARTSERIAL_H
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/RoboClaw/registers.h Mon Jan 10 20:38:41 2022 +0000 @@ -0,0 +1,87 @@ +#define ADR 0x80 +#define M1FORWARD 0 +#define M1BACKWARD 1 +#define SETMINMB 2 +#define SETMAXMB 3 +#define M2FORWARD 4 +#define M2BACKWARD 5 +#define M17BIT 6 +#define M27BIT 7 +#define MIXEDFORWARD 8 +#define MIXEDBACKWARD 9 +#define MIXEDRIGHT 10 +#define MIXEDLEFT 11 +#define MIXEDFB 12 +#define MIXEDLR 13 +#define GETM1ENC 16 +#define GETM2ENC 17 +#define GETM1SPEED 18 +#define GETM2SPEED 19 +#define RESETENC 20 +#define GETVERSION 21 +#define SETM1ENCCOUNT 22 +#define SETM2ENCCOUNT 23 +#define GETMBATT 24 +#define GETLBATT 25 +#define SETMINLB 26 +#define SETMAXLB 27 +#define SETM1PID 28 +#define SETM2PID 29 +#define GETM1ISPEED 30 +#define GETM2ISPEED 31 +#define M1DUTY 32 +#define M2DUTY 33 +#define MIXEDDUTY 34 +#define M1SPEED 35 +#define M2SPEED 36 +#define MIXEDSPEED 37 +#define M1SPEEDACCEL 38 +#define M2SPEEDACCEL 39 +#define MIXEDSPEEDACCEL 40 +#define M1SPEEDDIST 41 +#define M2SPEEDDIST 42 +#define MIXEDSPEEDDIST 43 +#define M1SPEEDACCELDIST 44 +#define M2SPEEDACCELDIST 45 +#define MIXEDSPEEDACCELDIST 46 +#define GETBUFFERS 47 +#define GETCURRENTS 49 +#define MIXEDSPEED2ACCEL 50 +#define MIXEDSPEED2ACCELDIST 51 +#define M1DUTYACCEL 52 +#define M2DUTYACCEL 53 +#define MIXEDDUTYACCEL 54 +#define READM1PID 55 +#define READM2PID 56 +#define SETMAINVOLTAGES 57 +#define SETLOGICVOLTAGES 58 +#define GETMINMAXMAINVOLTAGES 59 +#define GETMINMAXLOGICVOLTAGES 60 +#define SETM1POSPID 61 +#define SETM2POSPID 62 +#define READM1POSPID 63 +#define READM2POSPID 64 +#define M1SPEEDACCELDECCELPOS 65 +#define M2SPEEDACCELDECCELPOS 66 +#define MIXEDSPEEDACCELDECCELPOS 67 +#define SETM1DEFAULTACCEL 68 +#define SETM2DEFAULTACCEL 69 +#define SETPINFUNCTIONS 74 +#define GETPINFUNCTIONS 75 +#define RESTOREDEFAULTS 80 +#define GETTEMP 82 +#define GETTEMP2 83 +#define GETERROR 90 +#define GETENCODERMODE 91 +#define SETM1ENCODERMODE 92 +#define SETM2ENCODERMODE 93 +#define WRITENVM 94 +#define READNVM 95 +#define SETCONFIG 98 +#define GETCONFIG 99 +#define SETM1MAXCURRENT 133 +#define SETM2MAXCURRENT 134 +#define GETM1MAXCURRENT 135 +#define GETM2MAXCURRENT 136 +#define SETPWMMODE 148 +#define GETPWMMODE 149 \ No newline at end of file