Reaction Wheel Actuated Satellite Dynamics Test Platform
Diploma Thesis in Aerospace Engineering, January 2014
University of Applied Sciences Munich, Faculty 03
Electronics:
- 1x mbed NXP LPC 1768 Microcontroller
- 2x XBee S1 Radios + Sparkfun USB Adapter
- 1x CHR UM6-lt IMU
- 4x Graupner BEC 8 Motor Controllers
- 4x ROXXY 2826/09 Brushless Motors
- 1x Hacker TopFuel LiPo 1300mAh Battery
- 1x big Selfmade BreakOutBoard to connect all components
- 1x small BreakOutBoard to connect IMU
Hardware developed with Catia V5R20
Manufactoring Technology: Rapid Prototyping - EOS Formiga P110
Controlled via text based menu with DockLight
__________________
Revision 0:1447d2f773db, committed 2014-07-09
- Comitter:
- DimitriGruebel
- Date:
- Wed Jul 09 07:35:50 2014 +0000
- Commit message:
- Dynamics Test Platform
Changed in this revision
diff -r 000000000000 -r 1447d2f773db MODSERIAL/ChangeLog.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MODSERIAL/ChangeLog.c Wed Jul 09 07:35:50 2014 +0000 @@ -0,0 +1,165 @@ +/* $Id:$ + +1.23 25th July 2012 + + * LPC1768 code as was. This release includes "alpha" support for the LPC11U24 + +1.22 19th April 2012 + + * http://mbed.org/forum/bugs-suggestions/topic/2936/ + * Bug fix, protect important buffer pointers from IRQ corruption. + Credits: + Anthony Wieser http://mbed.org/users/WieserSoftwareLtd/ for the fix. + BlazeX http://mbed.org/users/BlazeX/ for the alert that a fix was needed! + +1.21 10 May 2011 + + * http://mbed.org/forum/mbed/topic/2264 + +1.20 26 April 2011 + + * Bug fix, not blocking on transmit + by Erik Petrich, http://mbed.org/forum/bugs-suggestions/topic/2200 + +1.19 20 April 2011 + + * Fixed some doxygen comment bugs. + +1.18 20 April 2011 + + * All callbacks now use MODSERIAL_callback (rather than Mbed's FunctionPointer[1] type) + to store and invoke it's callbacks. This allows MODSERIAL to pass a parameter + to callbacks. The function prototype is now void func(MODSERIAL_IRQ_INFO *q). + * Callbacks now pass a pointer to a MODSERIAL_IRQ_INFO class type. + This class holds a pointer to the MODSERIAL object that invoked the callback + thus freeing callbacks need to use the global variable of the original + MODSERIAL instance. + * MODSERIAL_IRQ_INFO also declares public functions that are protected within MODSERIAL + thus allowing certain functions to be restricted to callback context only. + * New function MODSERIAL_IRQ_INFO::rxDiscardLastChar() allows an rxCallback function + to remove the character that was just placed into the RX buffer. + + [1] http://mbed.org/users/AjK/libraries/FPointer/latest/docs/ + +1.17 08/Mar/2011 + Fixed a memory leak in the DMA code. + +1.16 - 12 Feb 2011 + + * Missed one, doh! + +1.15 - 12 Feb 2011 + + * Fixed some typos. + +1.14 - 7 Feb 2011 + + * Fixed a bug in __putc() that caused the output buffer pointer to + become corrupted. + +1.13 - 20/01/2011 + + * Added extra documentation. + * Fixed some typos. + +1.12 - 20/01/2011 + + * Added new "autoDetectChar()" function. To use:- + 1st: Add a callback to invoke when the char is detected:- + .attach(&detectedChar, MODSERIAL::RxAutoDetect); + 2nd: Send the char to detect. + .autoDectectChar('\n'); + Whenever that char goes into the RX buffer your callback will be invoked. + Added example2.cpp to demo a simple messaging system using this auto feature. + + +1.11 - 23/11/2010 + + * Fixed a minor issue with 1.10 missed an alteration of name change. + +1.10 - 23/11/2010 + + * Rename the DMA callback from attach_dma_complete() to attach_dmaSendComplete() + +1.9 - 23/11/2010 + + * Added support for DMA sending of characters. Required is + the MODDMA library module:- + http://mbed.org/users/AjK/libraries/MODDMA/latest + See example_dma.cpp for more information. + +1.8 - 22/11/2010 + + * Added code so that if a buffer is set to zero length then + MODSERIAL defaults to just using the FIFO for that stream + thus making the library "fall back" to teh same operation + that the Mbed Serial library performs. + * Removed dmaSend() function that should have been removed + at 1.7 + +1.7 - 21/11/2010 + + * Remove the DMA enum from MODSERIAL.h as it's not currently + ready for release. + * Added page doxygen comments. + +1.6 - 21/11/2010 + + * Version 1.5 solved a blocking problem on putc() when called + from another ISR. However, isr_tx() invokes a callback of it's + own when a byte is tranferred from TX buffer to TX FIFO. User + programs may interpret that as an IRQ callback. That's an ISR + call from within an existing ISR which is not good. So the + TxIrq callback from isr_tx is now conditional. It will only + be called when isr_tx() is actually within it's own ISR and + not when called from alternate ISR handlers. + +1.5 - 21/11/2010 + + * Calling putc() (or any derived function that uses it like + printf()) while inside an interrupt service routine can + cause the system to lock up if the TX buffer is full. This + is because bytes are only transferred from the TX buffer to + the TX FIFO via the TX ISR. If we are, say in an RX ISR already, + then the TX ISR will never trigger. The TX buffer stays full and + there is never space to putc() the byte. So, while putc() blocks + waiting for space it calls isr_tx() to ensure if TX FIFO space + becomes available it will move bytes from the TX buffer to TX + FIFO thus removing the blocking condition within putc(). + +1.4 - 21/11/2010 + + * Removed all the new DMA code. I wish mbed.org had proper SVN + versioning, I'm use to working in HEAD and BRANCHES after I've + released a project. Getting bug reports in current releases + while trying to dev new code is hard to manage without source + control of some type! + +1.3 - 21/11/2010 + + * Fixed a macro problem with txIsBusy() + * Started adding code to use "block data" sending using DMA + * Removed #include "IOMACROS.h" + +1.2 - 21/11/2010 + + * Removed unsed variables from flushBuffer() + * Fixed a bug where both RX AND TX fifos are cleared/reset + when just TX OR RX should be cleared. + * Fixed a bug that cleared IIR when in fact it should be left + alone so that any pending interrupt after flush is handled. + * Merged setBase() into init() as it wasn't required anywhere else. + * Changed init() to enforce _uidx is set by Serial to define the _base + address of the Uart in use. + +1.1 - 20/11/2010 + + * Added this file + * Removed cruft from GETC.cpp + * "teh" should be "the", why do my fingers do that? + +1.0 - 20/11/2010 + + * First release. + +*/ \ No newline at end of file
diff -r 000000000000 -r 1447d2f773db MODSERIAL/FLUSH.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MODSERIAL/FLUSH.cpp Wed Jul 09 07:35:50 2014 +0000 @@ -0,0 +1,47 @@ +/* + Copyright (c) 2010 Andy Kirkham + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +#include "MODSERIAL.h" +#include "MACROS.h" + +namespace AjK { + +void +MODSERIAL::flushBuffer(IrqType type) +{ + uint32_t ier = _IER; + switch(type) { + case TxIrq: _IER &= ~(1UL << 1); break; + case RxIrq: _IER &= ~(1UL << 0); break; + } + buffer_in[type] = 0; + buffer_out[type] = 0; + buffer_count[type] = 0; + buffer_overflow[type] = 0; + switch(type) { + case TxIrq: _FCR = MODSERIAL_FIFO_TX_RESET; break; + case RxIrq: _FCR = MODSERIAL_FIFO_RX_RESET; break; + } + _IER = ier; +} + +}; // namespace AjK ends
diff -r 000000000000 -r 1447d2f773db MODSERIAL/GETC.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MODSERIAL/GETC.cpp Wed Jul 09 07:35:50 2014 +0000 @@ -0,0 +1,65 @@ +/* + Copyright (c) 2010 Andy Kirkham + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +#include "MODSERIAL.h" +#include "MACROS.h" + +namespace AjK { + +int +MODSERIAL::__getc(bool block) +{ + // If no buffer is in use fall back to standard RX FIFO usage. + // Note, we must block in this case and ignore bool "block" + // so as to maintain compat with Mbed Serial. + if (buffer_size[RxIrq] == 0 || buffer[RxIrq] == (char *)NULL) { + while(! MODSERIAL_RBR_HAS_DATA ) ; + return (int)(_RBR & 0xFF); + } + + if (block) { while ( MODSERIAL_RX_BUFFER_EMPTY ) ; } // Blocks. + else if ( MODSERIAL_RX_BUFFER_EMPTY ) return -1; + + int c = buffer[RxIrq][buffer_out[RxIrq]]; + buffer_out[RxIrq]++; + if (buffer_out[RxIrq] >= buffer_size[RxIrq]) { + buffer_out[RxIrq] = 0; + } + + // If we have made space in the RX Buffer then copy over + // any characters in the RX FIFO that my reside there. + // Temporarily disable the RX IRQ so that we do not re-enter + // it under interrupts. + if ( ! MODSERIAL_RX_BUFFER_FULL ) { + uint32_t ier = _IER; + _IER &= ~(1UL << 0); + isr_rx(); + _IER = ier; + } + + __disable_irq(); + buffer_count[RxIrq]--; + __enable_irq(); + return c; +} + +}; // namespace AjK ends
diff -r 000000000000 -r 1447d2f773db MODSERIAL/INIT.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MODSERIAL/INIT.cpp Wed Jul 09 07:35:50 2014 +0000 @@ -0,0 +1,80 @@ +/* + Copyright (c) 2010 Andy Kirkham + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +#include "MODSERIAL.h" +#include "MACROS.h" + +namespace AjK { + +void +MODSERIAL::init( int txSize, int rxSize ) +{ + disableIrq(); + + callbackInfo.setSerial(this); + +#ifdef __LPC11UXX_H__ + + _base = LPC_USART; + +#else + switch(_serial.index) { + case 0: _base = LPC_UART0; break; + case 1: _base = LPC_UART1; break; + case 2: _base = LPC_UART2; break; + case 3: _base = LPC_UART3; break; + default : _base = NULL; break; + } +#endif + + dmaSendChannel = -1; + moddma_p = (void *)NULL; + + if (_base != NULL) { + buffer_size[RxIrq] = rxSize; + buffer[RxIrq] = rxSize > 0 ? (char *)malloc(buffer_size[RxIrq]) : (char *)NULL; + buffer_in[RxIrq] = 0; + buffer_out[RxIrq] = 0; + buffer_count[RxIrq] = 0; + buffer_overflow[RxIrq] = 0; + Serial::attach(this, &MODSERIAL::isr_rx, Serial::RxIrq); + + buffer_size[TxIrq] = txSize; + buffer[TxIrq] = txSize > 0 ? (char *)malloc(buffer_size[TxIrq]) : (char *)NULL; + buffer_in[TxIrq] = 0; + buffer_out[TxIrq] = 0; + buffer_count[TxIrq] = 0; + buffer_overflow[TxIrq] = 0; + Serial::attach(this, &MODSERIAL::isr_tx, Serial::TxIrq); + } + else { + error("MODSERIAL must have a defined UART to function."); + } + + _FCR = MODSERIAL_FIFO_ENABLE | MODSERIAL_FIFO_RX_RESET | MODSERIAL_FIFO_TX_RESET; + + auto_detect_char = 0; + + enableIrq(); +} + +}; // namespace AjK ends
diff -r 000000000000 -r 1447d2f773db MODSERIAL/ISR_RX.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MODSERIAL/ISR_RX.cpp Wed Jul 09 07:35:50 2014 +0000 @@ -0,0 +1,60 @@ +/* + Copyright (c) 2010 Andy Kirkham + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +#include "MODSERIAL.h" +#include "MACROS.h" + +namespace AjK { + +void +MODSERIAL::isr_rx(void) +{ + if (! _base || buffer_size[RxIrq] == 0 || buffer[RxIrq] == (char *)NULL) { + _isr[RxIrq].call(&this->callbackInfo); + return; + } + + while( MODSERIAL_RBR_HAS_DATA ) { + rxc = (char)(_RBR & 0xFF); + if ( MODSERIAL_RX_BUFFER_FULL ) { + buffer_overflow[RxIrq] = rxc; // Oh dear, no room in buffer. + _isr[RxOvIrq].call(&this->callbackInfo); + } + else { + if (buffer[RxIrq] != (char *)NULL) { + buffer[RxIrq][buffer_in[RxIrq]] = rxc; + buffer_count[RxIrq]++; + buffer_in[RxIrq]++; + if (buffer_in[RxIrq] >= buffer_size[RxIrq]) { + buffer_in[RxIrq] = 0; + } + } + _isr[RxIrq].call(&this->callbackInfo); + } + if (auto_detect_char == rxc) { + _isr[RxAutoDetect].call(&this->callbackInfo); + } + } +} + +}; // namespace AjK ends +
diff -r 000000000000 -r 1447d2f773db MODSERIAL/ISR_TX.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MODSERIAL/ISR_TX.cpp Wed Jul 09 07:35:50 2014 +0000 @@ -0,0 +1,54 @@ +/* + Copyright (c) 2010 Andy Kirkham + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +#include "MODSERIAL.h" +#include "MACROS.h" + +namespace AjK { + +void +MODSERIAL::isr_tx(bool doCallback) +{ + if (! _base || buffer_size[TxIrq] == 0 || buffer[TxIrq] == (char *)NULL) { + _isr[TxIrq].call(&this->callbackInfo); + return; + } + + while (! MODSERIAL_TX_BUFFER_EMPTY && MODSERIAL_THR_HAS_SPACE ) { + _THR = txc = (uint8_t)(buffer[TxIrq][buffer_out[TxIrq]]); + buffer_count[TxIrq]--; + buffer_out[TxIrq]++; + if (buffer_out[TxIrq] >= buffer_size[TxIrq]) { + buffer_out[TxIrq] = 0; + } + if (doCallback) _isr[TxIrq].call(&this->callbackInfo); + } + + if ( MODSERIAL_TX_BUFFER_EMPTY ) { + _IER = 1; + _isr[TxEmpty].call(&this->callbackInfo); + } +} + +}; // namespace AjK ends + +
diff -r 000000000000 -r 1447d2f773db MODSERIAL/MACROS.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MODSERIAL/MACROS.h Wed Jul 09 07:35:50 2014 +0000 @@ -0,0 +1,70 @@ +/* + Copyright (c) 2010 Andy Kirkham + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +#ifndef MODSERIAL_MACROS_H +#define MODSERIAL_MACROS_H + +#define MODSERIAL_RBR 0x00 +#define MODSERIAL_THR 0x00 +#define MODSERIAL_DLL 0x00 +#define MODSERIAL_IER 0x04 +#define MODSERIAL_DML 0x04 +#define MODSERIAL_IIR 0x08 +#define MODSERIAL_FCR 0x08 +#define MODSERIAL_LCR 0x0C +#define MODSERIAL_LSR 0x14 +#define MODSERIAL_SCR 0x1C +#define MODSERIAL_ACR 0x20 +#define MODSERIAL_ICR 0x24 +#define MODSERIAL_FDR 0x28 +#define MODSERIAL_TER 0x30 + +#define MODSERIAL_LSR_RDR (1UL << 0) +#define MODSERIAL_LSR_OE (1UL << 1) +#define MODSERIAL_LSR_PE (1UL << 2) +#define MODSERIAL_LSR_FE (1UL << 3) +#define MODSERIAL_LSR_BR (1UL << 4) +#define MODSERIAL_LSR_THRE (1UL << 5) +#define MODSERIAL_LSR_TEMT (1UL << 6) +#define MODSERIAL_LSR_RXFE (1UL << 7) + +#define MODSERIAL_FIFO_ENABLE 1 +#define MODSERIAL_FIFO_RX_RESET 2 +#define MODSERIAL_FIFO_TX_RESET 4 + +#define _RBR *((char *)_base+MODSERIAL_RBR) +#define _THR *((char *)_base+MODSERIAL_THR) +#define _IIR *((char *)_base+MODSERIAL_IIR) +#define _IER *((char *)_base+MODSERIAL_IER) +#define _LSR *((char *)_base+MODSERIAL_LSR) +#define _FCR *((char *)_base+MODSERIAL_FCR) + +#define MODSERIAL_TX_BUFFER_EMPTY (buffer_count[TxIrq]==0) +#define MODSERIAL_RX_BUFFER_EMPTY (buffer_count[RxIrq]==0) +#define MODSERIAL_TX_BUFFER_FULL (buffer_count[TxIrq]==buffer_size[TxIrq]) +#define MODSERIAL_RX_BUFFER_FULL (buffer_count[RxIrq]==buffer_size[RxIrq]) + +#define MODSERIAL_THR_HAS_SPACE ((int)_LSR&MODSERIAL_LSR_THRE) +#define MODSERIAL_TEMT_IS_EMPTY ((int)_LSR&MODSERIAL_LSR_TEMT) +#define MODSERIAL_RBR_HAS_DATA ((int)_LSR&MODSERIAL_LSR_RDR) + +#endif
diff -r 000000000000 -r 1447d2f773db MODSERIAL/MODSERIAL.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MODSERIAL/MODSERIAL.cpp Wed Jul 09 07:35:50 2014 +0000 @@ -0,0 +1,137 @@ +/* + Copyright (c) 2010 Andy Kirkham + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + + @file MODSERIAL.h + @purpose Extends Serial to provide fully buffered IO + @version 1.6 + @date Nov 2010 + @author Andy Kirkham +*/ + +#include "MODSERIAL.h" +#include "MACROS.h" + +namespace AjK { + +MODSERIAL::MODSERIAL( PinName tx, PinName rx, const char *name ) : Serial( tx, rx, name ) +{ + init( MODSERIAL_DEFAULT_TX_BUFFER_SIZE, MODSERIAL_DEFAULT_RX_BUFFER_SIZE ); +} + +MODSERIAL::MODSERIAL( PinName tx, PinName rx, int bufferSize, const char *name ) : Serial( tx, rx, name ) +{ + init( bufferSize, bufferSize ); +} + +MODSERIAL::MODSERIAL( PinName tx, PinName rx, int txSize, int rxSize, const char *name ) : Serial( tx, rx, name ) +{ + init( txSize, rxSize ); +} + +MODSERIAL::~MODSERIAL() +{ + disableIrq(); + if ( buffer[0] != NULL) free((char *)buffer[0] ); + if ( buffer[1] != NULL) free((char *)buffer[1] ); +} + +bool +MODSERIAL::txBufferFull( void ) +{ + return MODSERIAL_TX_BUFFER_FULL; +} + +bool +MODSERIAL::rxBufferFull( void ) +{ + return MODSERIAL_RX_BUFFER_FULL; +} + +bool +MODSERIAL::txBufferEmpty( void ) +{ + return MODSERIAL_TX_BUFFER_EMPTY; +} + +bool +MODSERIAL::rxBufferEmpty( void ) +{ + return MODSERIAL_RX_BUFFER_EMPTY; +} + +bool +MODSERIAL::txIsBusy( void ) +{ + return ( _LSR & ( 3UL << 5 ) == 0 ) ? true : false; +} + +void +MODSERIAL::disableIrq( void ) +{ + +#ifdef __LPC11UXX_H__ + NVIC_DisableIRQ( UART_IRQn ); +#else + switch(_serial.index) { + case 0: NVIC_DisableIRQ( UART0_IRQn ); break; + case 1: NVIC_DisableIRQ( UART1_IRQn ); break; + case 2: NVIC_DisableIRQ( UART2_IRQn ); break; + case 3: NVIC_DisableIRQ( UART3_IRQn ); break; + } +#endif +} + +void +MODSERIAL::enableIrq(void) +{ +#ifdef __LPC11UXX_H__ + NVIC_EnableIRQ( UART_IRQn ); +#else + switch( _serial.index ) { + case 0: NVIC_EnableIRQ( UART0_IRQn ); break; + case 1: NVIC_EnableIRQ( UART1_IRQn ); break; + case 2: NVIC_EnableIRQ( UART2_IRQn ); break; + case 3: NVIC_EnableIRQ( UART3_IRQn ); break; + } +#endif +} + +int +MODSERIAL::rxDiscardLastChar( void ) +{ + // This function can only be called indirectly from + // an rxCallback function. Therefore, we know we + // just placed a char into the buffer. + char c = buffer[RxIrq][buffer_in[RxIrq]]; + + if (buffer_count[RxIrq]) { + buffer_count[RxIrq]--; + buffer_in[RxIrq]--; + if (buffer_in[RxIrq] < 0) { + buffer_in[RxIrq] = buffer_size[RxIrq] - 1; + } + } + + return (int)c; +} + + +}; // namespace AjK ends
diff -r 000000000000 -r 1447d2f773db MODSERIAL/MODSERIAL.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MODSERIAL/MODSERIAL.h Wed Jul 09 07:35:50 2014 +0000 @@ -0,0 +1,1091 @@ +/* + Copyright (c) 2010 Andy Kirkham + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + + @file MODSERIAL.h + @purpose Extends Serial to provide fully buffered IO + @version see ChangeLog.c + @date Nov 2010 + @author Andy Kirkham +*/ + +#ifndef MODSERIAL_H +#define MODSERIAL_H + +/** @defgroup API The MODSERIAL API */ +/** @defgroup MISC Misc MODSERIAL functions */ +/** @defgroup INTERNALS MODSERIAL Internals */ + +#ifndef MODSERIAL_DEFAULT_RX_BUFFER_SIZE +#define MODSERIAL_DEFAULT_RX_BUFFER_SIZE 256 +#endif + +#ifndef MODSERIAL_DEFAULT_TX_BUFFER_SIZE +#define MODSERIAL_DEFAULT_TX_BUFFER_SIZE 256 +#endif + +#include "mbed.h" + +namespace AjK { + +// Forward reference. +class MODSERIAL; + +/** + * @author Andy Kirkham + * @see http://mbed.org/cookbook/MODSERIAL + * @see example3a.cpp + * @see example3b.cpp + * @see API + * + * <b>MODSERIAL_IRQ_INFO</b> is a class used to pass information (and access to protected + * MODSERIAL functions) to IRQ callbacks. + */ +class MODSERIAL_IRQ_INFO +{ +public: + friend class MODSERIAL; + + MODSERIAL *serial; + + MODSERIAL_IRQ_INFO() { serial = 0; } + + /** rxDiscardLastChar() + * + * Remove the last char placed into the rx buffer. + * This is an operation that can only be performed + * by an rxCallback function. + * @ingroup API + * @return The byte removed from the buffer. + */ + int rxDiscardLastChar(void); + +protected: + + /** setSerial() + * + * Used internally by MODSERIAL to set the "this" pointer + * of the MODSERIAL that created this object. + * @ingroup INTERNAL + * @param A pointer to a MODSERIAL object instance. + */ + void setSerial(MODSERIAL *s) { serial = s; } +}; + +// Forward reference dummy class. +class MODSERIAL_callback_dummy; + +/** + * @author Andy Kirkham + * @see http://mbed.org/cookbook/MODSERIAL + * @see example3a.cpp + * @see example3b.cpp + * @see API + * + * <b>MODSERIAL_callback</b> is a class used to hold application callbacks that + * MODSERIAL can invoke on certain events. + */ +class MODSERIAL_callback +{ +protected: + + //! C callback function pointer. + void (*c_callback)(MODSERIAL_IRQ_INFO *); + + //! C++ callback object/method pointer (the object part). + MODSERIAL_callback_dummy *obj_callback; + + //! C++ callback object/method pointer (the method part). + void (MODSERIAL_callback_dummy::*method_callback)(MODSERIAL_IRQ_INFO *); + +public: + + /** Constructor + */ + MODSERIAL_callback() { + c_callback = 0; + obj_callback = 0; + method_callback = 0; + } + + /** attach - Overloaded attachment function. + * + * Attach a C type function pointer as the callback. + * + * Note, the callback function prototype must be:- + * @code + * void myCallbackFunction(MODSERIAL_IRQ_INFO *); + * @endcode + * @param A C function pointer to call. + */ + void attach(void (*function)(MODSERIAL_IRQ_INFO *) = 0) { c_callback = function; } + + /** attach - Overloaded attachment function. + * + * Attach a C++ type object/method pointer as the callback. + * + * Note, the callback method prototype must be:- + * @code + * public: + * void myCallbackFunction(MODSERIAL_IRQ_INFO *); + * @endcode + * @param A C++ object pointer. + * @param A C++ method within the object to call. + */ + template<class T> + void attach(T* item, void (T::*method)(MODSERIAL_IRQ_INFO *)) { + obj_callback = (MODSERIAL_callback_dummy *)item; + method_callback = (void (MODSERIAL_callback_dummy::*)(MODSERIAL_IRQ_INFO *))method; + } + + /** call - Overloaded callback initiator. + * + * call the callback function. + * + * @param A pointer to a MODSERIAL_IRQ_INFO object. + */ + void call(MODSERIAL_IRQ_INFO *arg) { + if (c_callback != 0) { + (*c_callback)(arg); + } + else { + if (obj_callback != 0 && method_callback != 0) { + (obj_callback->*method_callback)(arg); + } + } + } +}; + +/** + * @author Andy Kirkham + * @see http://mbed.org/cookbook/MODSERIAL + * @see http://mbed.org/handbook/Serial + * @see example1.cpp + * @see example2.cpp + * @see example3a.cpp + * @see example3b.cpp + * @see example_dma.cpp + * @see API + * + * <b>MODSERIAL</b> extends the Mbed library <a href="/handbook/Serial">Serial</a> to provide fully buffered + * TX and RX streams. Buffer length is fully customisable. + * + * Before using MODSERIAL users should be familar with Mbed's standard <a href="/handbook/Serial">Serial</a> + * library object. MODSERIAL is a direct "drop in" replacement for <a href="/handbook/Serial">Serial</a>. Where + * previously Serial was used, MODSERIAL can be used as adirect replacement instantly offering standard + * TX and RX buffering. By default, both TX and RX buffers are 256 bytes in length. + * + * @image html /media/uploads/mbedofficial/serial_interfaces.png + * + * Standard example: + * @code + * #include "mbed.h" + * #include "MODSERIAL.h" + * + * MODSERIAL pc(USBTX, USBRX); // tx, rx + * + * int main() { + * pc.printf("Hello World!"); + * while(1) { + * pc.putc(pc.getc() + 1); + * } + * } + * @endcode + * + * Example with alternate buffer length: + * @code + * #include "mbed.h" + * #include "MODSERIAL.h" + * + * // Make TX and RX buffers 512byes in length + * MODSERIAL pc(USBTX, USBRX, 512); // tx, rx + * + * int main() { + * pc.printf("Hello World!"); + * while(1) { + * pc.putc(pc.getc() + 1); + * } + * } + * @endcode + * + * Example with alternate buffer length: + * @code + * #include "mbed.h" + * #include "MODSERIAL.h" + * + * // Make TX 1024bytes and RX 512byes in length + * MODSERIAL pc(USBTX, USBRX, 1024, 512); // tx, rx + * + * int main() { + * pc.printf("Hello World!"); + * while(1) { + * pc.putc(pc.getc() + 1); + * } + * } + * @endcode + */ +class MODSERIAL : public Serial +{ +public: + + // Allow instances of MODSERIAL_IRQ_INFO to use protected properties and methods. + friend class MODSERIAL_IRQ_INFO; + + //! A copy of the Serial parity enum + /** @see http://mbed.org/projects/libraries/api/mbed/trunk/Serial#Serial.format */ + enum Parity { + None = 0 + , Odd + , Even + , Forced1 + , Forced0 + }; + + //! A copy of the Serial IrqType enum + enum IrqType { + RxIrq = 0 + , TxIrq + , RxOvIrq + , TxOvIrq + , TxEmpty + , RxAutoDetect + , NumOfIrqTypes + }; + + //! Non-blocking functions return code. + enum Result { + Ok = 0 /*!< Ok. */ + , NoMemory = -1 /*!< Memory allocation failed. */ + , NoChar = -1 /*!< No character in buffer. */ + , BufferOversize = -2 /*!< Oversized buffer. */ + }; + + /** + * The MODSERIAL constructor is used to initialise the serial object. + * + * @param tx PinName of the TX pin. + * @param rx PinName of the TX pin. + * @param name An option name for RPC usage. + */ + MODSERIAL(PinName tx, PinName rx, const char *name = NULL); + + /** + * The MODSERIAL constructor is used to initialise the serial object. + * + * @param tx PinName of the TX pin. + * @param rx PinName of the TX pin. + * @param bufferSize Integer of the TX and RX buffer sizes. + * @param name An option name for RPC usage. + */ + MODSERIAL(PinName tx, PinName rx, int bufferSize, const char *name = NULL); + + /** + * The MODSERIAL constructor is used to initialise the serial object. + * + * @param tx PinName of the TX pin. + * @param rx PinName of the TX pin. + * @param txBufferSize Integer of the TX buffer sizes. + * @param rxBufferSize Integer of the RX buffer sizes. + * @param name An option name for RPC usage. + */ + MODSERIAL(PinName tx, PinName rx, int txBufferSize, int rxBufferSize, const char *name = NULL); + + virtual ~MODSERIAL(); + + /** + * Function: attach + * + * The Mbed standard <a href="/handbook/Serial">Serial</a> library object allows an interrupt callback + * to be made when a byte is received by the TX or RX UART hardware. MODSERIAL traps these interrupts + * to enable it's buffering system. However, after the byte has been received/sent under interrupt control, + * MODSERIAL can callback a user function as a notification of the interrupt. Note, user code should not + * directly interact with the Uart hardware, MODSERIAL does that, instead, MODSERIAL API functions should + * be used. + * + * <b>Note</b>, a character is written out then, if there is room in the TX FIFO and the TX buffer is empty, + * putc() will put the character directly into THR (the output holding register). If the TX FIFO is full and + * cannot accept the character, it is placed into the TX output buffer. The TX interrupts are then enabled + * so that when the TX FIFO empties, the TX buffer is then transferred to the THR FIFO. The TxIrq will ONLY + * be activated when this transfer of a character from BUFFER to THR FIFO takes place. If your character + * throughput is not high bandwidth, then the 16 byte TX FIFO may be enough and the TX output buffer may + * never come into play. + * + * @code + * #include "mbed.h" + * #include "MODSERIAL.h" + * + * DigitalOut led1(LED1); + * DigitalOut led2(LED2); + * DigitalOut led3(LED3); + * + * // To test, connect p9 to p10 as a loopback. + * MODSERIAL pc(p9, p10); + * + * // This function is called when a character goes into the TX buffer. + * void txCallback(void) { + * led2 = !led2; + * } + * + * // This function is called when a character goes into the RX buffer. + * void rxCallback(void) { + * led3 = !led3; + * } + * + * int main() { + * pc.baud(115200); + * pc.attach(&txCallback, MODSERIAL::TxIrq); + * pc.attach(&rxCallback, MODSERIAL::RxIrq); + * + * while(1) { + * led1 = !led1; + * wait(0.5); + * pc.putc('A'); + * wait(0.5); + * } + * ] + * @endcode + * + * @ingroup API + * @param fptr A pointer to a void function, or 0 to set as none + * @param type Which serial interrupt to attach the member function to (Seriall::RxIrq for receive, TxIrq for transmit buffer empty) + */ + void attach(void (*fptr)(MODSERIAL_IRQ_INFO *), IrqType type = RxIrq) { _isr[type].attach(fptr); } + + /** + * Function: attach + * + * The Mbed standard <a href="/handbook/Serial">Serial</a> library object allows an interrupt callback + * to be made when a byte is received by the TX or RX UART hardware. MODSERIAL traps these interrupts + * to enable it's buffering system. However, after the byte has been received/sent under interrupt control, + * MODSERIAL can callback a user function as a notification of the interrupt. Note, user code should not + * directly interact with the Uart hardware, MODSERIAL does that, instead, MODSERIAL API functions should + * be used. + * + * <b>Note</b>, a character is written out then, if there is room in the TX FIFO and the TX buffer is empty, + * putc() will put the character directly into THR (the output holding register). If the TX FIFO is full and + * cannot accept the character, it is placed into the TX output buffer. The TX interrupts are then enabled + * so that when the TX FIFO empties, the TX buffer is then transferred to the THR FIFO. The TxIrq will ONLY + * be activated when this transfer of a character from BUFFER to THR FIFO takes place. If your character + * throughput is not high bandwidth, then the 16 byte TX FIFO may be enough and the TX output buffer may + * never come into play. + * + * @code + * #include "mbed.h" + * #include "MODSERIAL.h" + * + * DigitalOut led1(LED1); + * DigitalOut led2(LED2); + * DigitalOut led3(LED3); + * + * // To test, connect p9 to p10 as a loopback. + * MODSERIAL pc(p9, p10); + * + * class Foo { + * public: + * // This method is called when a character goes into the TX buffer. + * void txCallback(void) { led2 = !led2; } + * + * // This method is called when a character goes into the RX buffer. + * void rxCallback(void) { led3 = !led3; } + * }; + * + * Foo foo; + * + * int main() { + * pc.baud(115200); + * pc.attach(&foo, &Foo::txCallback, MODSERIAL::TxIrq); + * pc.attach(&foo, &Foo::rxCallback, MODSERIAL::RxIrq); + * + * while(1) { + * led1 = !led1; + * wait(0.5); + * pc.putc('A'); + * wait(0.5); + * } + * ] + * @endcode + * + * @ingroup API + * @param tptr A pointer to the object to call the member function on + * @param mptr A pointer to the member function to be called + * @param type Which serial interrupt to attach the member function to (Seriall::RxIrq for receive, TxIrq for transmit buffer empty) + */ + template<typename T> + void attach(T* tptr, void (T::*mptr)(MODSERIAL_IRQ_INFO *), IrqType type = RxIrq) { + if((mptr != 0) && (tptr != 0)) { + _isr[type].attach(tptr, mptr); + } + } + + /** + * @see attach + * @ingroup API + */ + void connect(void (*fptr)(MODSERIAL_IRQ_INFO *), IrqType type = RxIrq) { _isr[RxIrq].attach(fptr); } + + /** + * @see attach + * @ingroup API + */ + template<typename T> + void connect(T* tptr, void (T::*mptr)(MODSERIAL_IRQ_INFO *), IrqType type = RxIrq) { + if((mptr != 0) && (tptr != 0)) { + _isr[type].attach(tptr, mptr); + } + } + + /** + * Function: writeable + * + * Determine if there is space available to write a byte + * + * @ingroup API + * @return 1 if there is space to write a character, else 0 + */ + int writeable() { return txBufferFull() ? 0 : 1; } + + /** + * Function: readable + * + * Determine if there is a byte available to read + * + * @ingroup API + * @return 1 if there is a character available to read, else 0 + */ + int readable() { return rxBufferEmpty() ? 0 : 1; } + + /** + * Function: txBufferSane + * + * Determine if the TX buffer has been initialized. + * + * @ingroup API + * @return true if the buffer is initialized, else false + */ + bool txBufferSane(void) { return buffer[TxIrq] != (char *)NULL ? true : false; } + + /** + * Function: rxBufferSane + * + * Determine if the RX buffer has been initialized. + * + * @ingroup API + * @return true if the buffer is initialized, else false + */ + bool rxBufferSane(void) { return buffer[TxIrq] != (char *)NULL ? true : false; } + + /** + * Function: txBufferGetCount + * + * Returns how many bytes are in the TX buffer + * + * @ingroup API + * @return The number of bytes in the TX buffer + */ + int txBufferGetCount(void) { return buffer_count[TxIrq]; } + + /** + * Function: rxBufferGetCount + * + * Returns how many bytes are in the RX buffer + * + * @ingroup API + * @return The number of bytes in the RX buffer + */ + int rxBufferGetCount(void) { return buffer_count[RxIrq]; } + + /** + * Function: txBufferGetSize + * + * Returns the current size of the TX buffer + * + * @ingroup API + * @return The length iof the TX buffer in bytes + */ + int txBufferGetSize(int size) { return buffer_size[TxIrq]; } + + /** + * Function: rxBufferGetSize + * + * Returns the current size of the RX buffer + * + * @ingroup API + * @return The length iof the RX buffer in bytes + */ + int rxBufferGetSize(int size) { return buffer_size[RxIrq]; } + + /** + * Function: txBufferFull + * + * Is the TX buffer full? + * + * @ingroup API + * @return true if the TX buffer is full, otherwise false + */ + bool txBufferFull(void); + + /** + * Function: rxBufferFull + * + * Is the RX buffer full? + * + * @ingroup API + * @return true if the RX buffer is full, otherwise false + */ + bool rxBufferFull(void); + + /** + * Function: txBufferEmpty + * + * Is the TX buffer empty? + * + * @ingroup API + * @return true if the TX buffer is empty, otherwise false + */ + bool txBufferEmpty(void); + + /** + * Function: rxBufferEmpty + * + * Is the RX buffer empty? + * + * @ingroup API + * @return true if the RX buffer is empty, otherwise false + */ + bool rxBufferEmpty(void); + + /** + * Function: txBufferSetSize + * + * Change the TX buffer size. + * + * @see Result + * @ingroup API + * @param size The new TX buffer size in bytes. + * @param m Perform a memory sanity check. Errs the Mbed if memory alloc fails. + * @return Result Ok on success. + */ + int txBufferSetSize(int size, bool m) { return resizeBuffer(size, TxIrq, m); } + + /** + * Function: rxBufferSetSize + * + * Change the RX buffer size. + * + * @see Result + * @ingroup API + * @param size The new RX buffer size in bytes. + * @param m Perform a memory sanity check. Errs the Mbed if memory alloc fails. + * @return Result Ok on success. + */ + int rxBufferSetSize(int size, bool m) { return resizeBuffer(size, RxIrq, m); } + + /** + * Function: txBufferSetSize + * + * Change the TX buffer size. + * Always performs a memory sanity check, halting the Mbed on failure. + * + * @see Result + * @ingroup API + * @param size The new TX buffer size in bytes. + * @return Result Ok on success. + */ + int txBufferSetSize(int size) { return resizeBuffer(size, TxIrq, true); } + + /** + * Function: rxBufferSetSize + * + * Change the RX buffer size. + * Always performs a memory sanity check, halting the Mbed on failure. + * + * @see Result + * @ingroup API + * @param size The new RX buffer size in bytes. + * @return Result Ok on success. + */ + int rxBufferSetSize(int size) { return resizeBuffer(size, RxIrq, true); } + + /** + * Function: txBufferFlush + * + * Remove all bytes from the TX buffer. + * @ingroup API + */ + void txBufferFlush(void) { flushBuffer(TxIrq); } + + /** + * Function: rxBufferFlush + * + * Remove all bytes from the RX buffer. + * @ingroup API + */ + void rxBufferFlush(void) { flushBuffer(RxIrq); } + + /** + * Function: getcNb + * + * Like getc() but is non-blocking. If no bytes are in the RX buffer this + * function returns Result::NoChar (-1) + * + * @ingroup API + * @return A byte from the RX buffer or Result::NoChar (-1) if bufer empty. + */ + int getcNb() { return __getc(false); } + + /** + * Function: getc + * + * Overloaded version of Serial::getc() + * + * This function blocks (if the RX buffer is empty the function will wait for a + * character to arrive and then return that character). + * + * @ingroup API + * @return A byte from the RX buffer + */ + int getc() { return __getc(true); } + + /** + * Function: txGetLastChar + * + * Rteurn the last byte to pass through the TX interrupt handler. + * + * @ingroup MISC + * @return The byte + */ + char txGetLastChar(void) { return txc; } + + /** + * Function: rxGetLastChar + * + * Return the last byte to pass through the RX interrupt handler. + * + * @ingroup MISC + * @return The byte + */ + char rxGetLastChar(void) { return rxc; } + + /** + * Function: txIsBusy + * + * If the Uart is still actively sending characters this + * function will return true. + * + * @ingroup API + * @return bool + */ + bool txIsBusy(void); + + /** + * Function: autoDetectChar + * + * Set the char that, if seen incoming, invokes the AutoDetectChar callback. + * + * @ingroup API + * @param int c The character to detect. + */ + void autoDetectChar(char c) { auto_detect_char = c; } + + /** + * Function: move + * + * Move contents of RX buffer to external buffer. Stops if "end" detected. + * + * @ingroup API + * @param char *s The destination buffer address + * @param int max The maximum number of chars to move. + * @param char end If this char is detected stop moving. + */ + int move(char *s, int max, char end) { + int counter = 0; + char c; + while(readable()) { + c = getc(); + if (c == end) break; + *(s++) = c; + counter++; + if (counter == max) break; + } + return counter; + } + + /** + * Function: move (overloaded) + * + * Move contents of RX buffer to external buffer. Stops if auto_detect_char detected. + * + * @ingroup API + * @param int max The maximum number of chars to move. + * @param char *s The destination buffer address + */ + int move(char *s, int max) { + return move(s, max, auto_detect_char); + } + + #if 0 // Inhereted from Serial/Stream, for documentation only + /** + * Function: putc + * + * Write a character + * Inhereted from Serial/Stream + * + * @see http://mbed.org/projects/libraries/api/mbed/trunk/Serial#Serial.putc + * @ingroup API + * @param c The character to write to the serial port + */ + int putc(int c); + #endif + + #if 0 // Inhereted from Serial/Stream, for documentation only + /** + * Function: printf + * + * Write a formated string + * Inhereted from Serial/Stream + * + * @see http://mbed.org/projects/libraries/api/mbed/trunk/Serial#Serial.printf + * @ingroup API + * @param format A printf-style format string, followed by the variables to use in formating the string. + */ + int printf(const char* format, ...); + #endif + + #if 0 // Inhereted from Serial/Stream, for documentation only + /** + * Function: scanf + * + * Read a formated string + * Inhereted from Serial/Stream + * + * @see http://mbed.org/projects/libraries/api/mbed/trunk/Serial#Serial.scanf + * @ingroup API + * @param format - A scanf-style format string, followed by the pointers to variables to store the results. + */ + int scanf(const char* format, ...); + #endif + +protected: + /** + * Used to pass information to callbacks. + * @ingroup INTERNALS + */ + MODSERIAL_IRQ_INFO callbackInfo; + + /** + * Remove the last char placed into the rx buffer. + * This is an operation that can only be performed + * by an rxCallback function. To protect the buffers + * this function is defined protected so that a + * regular application cannot call it directly. It + * can only be called by the public version within a + * MODSERIAL_IRQ_INFO class. + * @ingroup INTERNALS + * @return The byte removed from the buffer. + */ + int rxDiscardLastChar(void); + +private: + + /** + * A pointer to the UART peripheral base address being used. + * @ingroup INTERNALS + */ + void *_base; + + /** + * The last byte to pass through the TX IRQ handler. + * @ingroup INTERNALS + */ + volatile char txc; + + /** + * The last byte to pass through the RX IRQ handler. + * @ingroup INTERNALS + */ + volatile char rxc; + + /** + * Pointers to the TX and RX buffers. + * @ingroup INTERNALS + */ + volatile char *buffer[2]; + + /** + * Buffer in pointers. + * @ingroup INTERNALS + */ + volatile int buffer_in[2]; + + /** + * Buffer out pointers. + * @ingroup INTERNALS + */ + volatile int buffer_out[2]; + + /** + * Buffer lengths. + * @ingroup INTERNALS + */ + volatile int buffer_size[2]; + + /** + * Buffer content counters. + * @ingroup INTERNALS + */ + volatile int buffer_count[2]; + + /** + * Buffer overflow. + * @ingroup INTERNALS + */ + volatile int buffer_overflow[2]; + + /** + * Auto-detect character. + * @ingroup INTERNALS + */ + volatile char auto_detect_char; + + /** + * Callback system. + * @ingroup INTERNALS + */ + MODSERIAL_callback _isr[NumOfIrqTypes]; + + /** + * TX Interrupt Service Routine. + * @ingroup INTERNALS + */ + void isr_tx(bool doCallback); + + /** + * TX Interrupt Service Routine stub version. + * @ingroup INTERNALS + */ + void isr_tx(void) { isr_tx(true); } + + + /** + * RX Interrupt Service Routine. + * @ingroup INTERNALS + */ + void isr_rx(void); + + /** + * Disable the interrupts for this Uart. + * @ingroup INTERNALS + */ + void disableIrq(void); + + /** + * Enable the interrupts for this Uart. + * @ingroup INTERNALS + */ + void enableIrq(void); + + /** + * Get a character from the RX buffer + * @ingroup INTERNALS + * @param bool True to block (wait for input) + * @return A byte from the buffer. + */ + int __getc(bool); + + /** + * Put a character from the TX buffer + * @ingroup INTERNALS + * @param bool True to block (wait for space in the TX buffer if full) + * @return 0 on success + */ + int __putc(int c, bool); + + /** + * Function: _putc + * Overloaded virtual function. + */ + virtual int _putc(int c) { return __putc(c, true); } + + /** + * Function: _getc + * Overloaded virtual function. + */ + virtual int _getc() { return __getc(true); } + + /** + * Function: init + * Initialize the MODSERIAL object + * @ingroup INTERNALS + */ + void init(int txSize, int rxSize); + + /** + * Function: flushBuffer + * @ingroup INTERNALS + */ + void flushBuffer(IrqType type); + + /** + * Function: resizeBuffer + * @ingroup INTERNALS + */ + int resizeBuffer(int size, IrqType type = RxIrq, bool memory_check = true); + + /** + * Function: downSizeBuffer + * @ingroup INTERNALS + */ + int downSizeBuffer(int size, IrqType type, bool memory_check); + + /** + * Function: upSizeBuffer + * @ingroup INTERNALS + */ + int upSizeBuffer(int size, IrqType type, bool memory_check); + + /* + * If MODDMA is available the compile in code to handle sending + * an arbitary char buffer. Note, the parts before teh #ifdef + * are declared so that MODSERIAL can access then even if MODDMA + * isn't avaiable. Since MODDMA.h is only available at this point + * all DMA functionality must be declared inline in the class + * definition. + */ +public: + + int dmaSendChannel; + void *moddma_p; + +#ifdef MODDMA_H + + MODDMA_Config *config; + + /** + * Set the "void pointer" moddma_p to be a pointer to a + * MODDMA controller class instance. Used to manage the + * data transfer of DMA configurations. + * + * @ingroup API + * @param p A pointer to "the" instance of MODDMA. + */ + void MODDMA(MODDMA *p) { moddma_p = p; } + + /** + * Send a char buffer to the Uarts TX system + * using DMA. This blocks regular library + * sending. + * + * @param buffer A char buffer of bytes to send. + * @param len The length of the buffer to send. + * @param dmaChannel The DMA channel to use, defaults to 7 + * @return MODDMA::Status MODDMA::ok if all went ok + */ + int dmaSend(char *buffer, int len, int dmaChannel = 7) + { + if (moddma_p == (void *)NULL) return -2; + class MODDMA *dma = (class MODDMA *)moddma_p; + + dmaSendChannel = dmaChannel & 0x7; + + uint32_t conn = MODDMA::UART0_Tx; + switch(_serial.index) { + case 0: conn = MODDMA::UART0_Tx; break; + case 1: conn = MODDMA::UART1_Tx; break; + case 2: conn = MODDMA::UART2_Tx; break; + case 3: conn = MODDMA::UART3_Tx; break; + } + + config = new MODDMA_Config; + config + ->channelNum ( (MODDMA::CHANNELS)(dmaSendChannel & 0x7) ) + ->srcMemAddr ( (uint32_t) buffer ) + ->transferSize ( len ) + ->transferType ( MODDMA::m2p ) + ->dstConn ( conn ) + ->attach_tc ( this, &MODSERIAL::dmaSendCallback ) + ->attach_err ( this, &MODSERIAL::dmaSendCallback ) + ; // config end + + // Setup the configuration. + if (dma->Setup(config) == 0) { + return -1; + } + + //dma.Enable( MODDMA::Channel_0 ); + dma->Enable( config->channelNum() ); + return MODDMA::Ok; + } + + /** + * Attach a callback to the DMA completion. + * + * @ingroup API + * @param fptr A function pointer to call + * @return this + */ + void attach_dmaSendComplete(void (*fptr)(MODSERIAL_IRQ_INFO *)) { + _isrDmaSendComplete.attach(fptr); + } + + /** + * Attach a callback to the DMA completion. + * + * @ingroup API + * @param tptr A template pointer to the calling object + * @param mptr A method pointer within the object to call. + * @return this + */ + template<typename T> + void attach_dmaSendComplete(T* tptr, void (T::*mptr)(MODSERIAL_IRQ_INFO *)) { + if((mptr != NULL) && (tptr != NULL)) { + _isrDmaSendComplete.attach(tptr, mptr); + } + } + + MODSERIAL_callback _isrDmaSendComplete; + +protected: + /** + * Callback for dmaSend(). + */ + void dmaSendCallback(void) + { + if (moddma_p == (void *)NULL) return; + class MODDMA *dma = (class MODDMA *)moddma_p; + + MODDMA_Config *config = dma->getConfig(); + dma->haltAndWaitChannelComplete( (MODDMA::CHANNELS)config->channelNum()); + dma->Disable( (MODDMA::CHANNELS)config->channelNum() ); + if (dma->irqType() == MODDMA::TcIrq) dma->clearTcIrq(); + if (dma->irqType() == MODDMA::ErrIrq) dma->clearErrIrq(); + dmaSendChannel = -1; + _isrDmaSendComplete.call(&this->callbackInfo); + delete(config); + } + +#endif // MODDMA_H + +}; + +}; // namespace AjK ends + +using namespace AjK; + +#endif
diff -r 000000000000 -r 1447d2f773db MODSERIAL/MODSERIAL_IRQ_INFO.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MODSERIAL/MODSERIAL_IRQ_INFO.cpp Wed Jul 09 07:35:50 2014 +0000 @@ -0,0 +1,38 @@ +/* + Copyright (c) 2010 Andy Kirkham + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + + @file MODSERIAL_IRQ_INFO.cpp + @author Andy Kirkham +*/ + +#include "MODSERIAL.h" + +namespace AjK { + +int +MODSERIAL_IRQ_INFO::rxDiscardLastChar(void) +{ + if (!serial) return -1; + + return serial->rxDiscardLastChar(); +} + +}; // namespace AjK ends
diff -r 000000000000 -r 1447d2f773db MODSERIAL/PUTC.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MODSERIAL/PUTC.cpp Wed Jul 09 07:35:50 2014 +0000 @@ -0,0 +1,81 @@ +/* + Copyright (c) 2010 Andy Kirkham + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +#include "MODSERIAL.h" +#include "MACROS.h" + +namespace AjK { + +int +MODSERIAL::__putc(int c, bool block) { + + // If no buffer is in use fall back to standard TX FIFO usage. + // Note, we must block in this case and ignore bool "block" + // so as to maintain compat with Mbed Serial. + if (buffer[TxIrq] == (char *)NULL || buffer_size[TxIrq] == 0) { + while (! MODSERIAL_THR_HAS_SPACE) ; // Wait for space in the TX FIFO. + _THR = (uint32_t)c; + return 0; + } + + if ( MODSERIAL_THR_HAS_SPACE && MODSERIAL_TX_BUFFER_EMPTY && dmaSendChannel == -1 ) { + _THR = (uint32_t)c; + } + else { + if (block) { + uint32_t ier = _IER; _IER = 1; + while ( MODSERIAL_TX_BUFFER_FULL ) { // Blocks! + // If putc() is called from an ISR then we are stuffed + // because in an ISR no bytes from the TX buffer will + // get transferred to teh TX FIFOs while we block here. + // So, to work around this, instead of sitting in a + // loop waiting for space in the TX buffer (which will + // never happen in IRQ context), check to see if the + // TX FIFO has space available to move bytes from the + // TX buffer to TX FIFO to make space. The easiest way + // to do this is to poll the isr_tx() function while we + // are blocking. + isr_tx(false); + } + _IER = ier; + } + else if( MODSERIAL_TX_BUFFER_FULL ) { + buffer_overflow[TxIrq] = c; // Oh dear, no room in buffer. + _isr[TxOvIrq].call(&this->callbackInfo); + return -1; + } + _IER &= ~2; + buffer[TxIrq][buffer_in[TxIrq]] = c; + __disable_irq(); + buffer_count[TxIrq]++; + __enable_irq(); + buffer_in[TxIrq]++; + if (buffer_in[TxIrq] >= buffer_size[TxIrq]) { + buffer_in[TxIrq] = 0; + } + _IER |= 2; + } + + return 0; +} + +}; // namespace AjK ends
diff -r 000000000000 -r 1447d2f773db MODSERIAL/RESIZE.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MODSERIAL/RESIZE.cpp Wed Jul 09 07:35:50 2014 +0000 @@ -0,0 +1,123 @@ +/* + Copyright (c) 2010 Andy Kirkham + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +#include "MODSERIAL.h" +#include "MACROS.h" + +namespace AjK { + +int +MODSERIAL::resizeBuffer(int size, IrqType type, bool memory_check) +{ + int rval = Ok; + + // If the requested size is the same as the current size there's nothing to do, + // just continue to use the same buffer as it's fine as it is. + if (buffer_size[type] == size) return rval; + + // Make sure the ISR cannot use the buffers while we are manipulating them. + disableIrq(); + + // If the requested buffer size is larger than the current size, + // attempt to create a new buffer and use it. + if (buffer_size[type] < size) { + rval = upSizeBuffer(size, type, memory_check); + } + else if (buffer_size[type] > size) { + rval = downSizeBuffer(size, type, memory_check); + } + + // Start the ISR system again with the new buffers. + enableIrq(); + + return rval; +} + +int +MODSERIAL::downSizeBuffer(int size, IrqType type, bool memory_check) +{ + if (size >= buffer_count[type]) { + return BufferOversize; + } + + char *s = (char *)malloc(size); + + if (s == (char *)NULL) { + if (memory_check) { + error("Failed to allocate memory for %s buffer", type == TxIrq ? "TX" : "RX"); + } + return NoMemory; + } + + int c, new_in = 0; + + do { + c = __getc(false); + if (c != -1) s[new_in++] = (char)c; + if (new_in >= size) new_in = 0; + } + while (c != -1); + + free((char *)buffer[type]); + buffer[type] = s; + buffer_in[type] = new_in; + buffer_out[type] = 0; + return Ok; +} + +int +MODSERIAL::upSizeBuffer(int size, IrqType type, bool memory_check) +{ + char *s = (char *)malloc(size); + + if (s == (char *)NULL) { + if (memory_check) { + error("Failed to allocate memory for %s buffer", type == TxIrq ? "TX" : "RX"); + } + return NoMemory; + } + + if (buffer_count[type] == 0) { // Current buffer empty? + free((char *)buffer[type]); + buffer[type] = s; + buffer_in[type] = 0; + buffer_out[type] = 0; + } + else { // Copy the current contents into the new buffer. + int c, new_in = 0; + do { + c = __getc(false); + if (c != -1) s[new_in++] = (char)c; + if (new_in >= size) new_in = 0; // Shouldn't happen, but be sure. + } + while (c != -1); + free((char *)buffer[type]); + buffer[type] = s; + buffer_in[type] = new_in; + buffer_out[type] = 0; + } + + buffer_size[type] = size; + return Ok; +} + +}; // namespace AjK ends
diff -r 000000000000 -r 1447d2f773db MODSERIAL/example1.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MODSERIAL/example1.cpp Wed Jul 09 07:35:50 2014 +0000 @@ -0,0 +1,120 @@ +#ifdef COMPILE_EXAMPLE1_CODE_MODSERIAL + +/* + * To run this test program, link p9 to p10 so the Serial loops + * back and receives characters it sends. + */ + +#include "mbed.h" +#include "MODSERIAL.h" + +DigitalOut led1(LED1); +DigitalOut led2(LED2); +DigitalOut led3(LED3); +DigitalOut led4(LED4); + +MODSERIAL pc(USBTX, USBRX); + +/* + * As experiement, you can define MODSERIAL as show here and see what + * effects it has on the LEDs. + * + * MODSERIAL uart(TX_PIN, RX_PIN, 512); + * With this, the 512 characters sent can straight into the buffer + * vary quickly. This means LED1 is only on briefly as the TX buffer + * fills. + * + * MODSERIAL uart(TX_PIN, RX_PIN, 32); + * With this, the buffer is smaller than the default 256 bytes and + * therefore LED1 stays on much longer while the system waits for + * room in the TX buffer. + */ +MODSERIAL uart(TX_PIN, RX_PIN); + +// This function is called when a character goes from the TX buffer +// to the Uart THR FIFO register. +void txCallback(MODSERIAL_IRQ_INFO *q) { + led2 = !led2; +} + +// This function is called when TX buffer goes empty +void txEmpty(MODSERIAL_IRQ_INFO *q) { + led2 = 0; + pc.puts(" Done. "); +} + +// This function is called when a character goes into the RX buffer. +void rxCallback(MODSERIAL_IRQ_INFO *q) { + led3 = !led3; + pc.putc(uart.getc()); +} + +int main() { + int c = 'A'; + + // Ensure the baud rate for the PC "USB" serial is much + // higher than "uart" baud rate below. + pc.baud(PC_BAUD); + + // Use a deliberatly slow baud to fill up the TX buffer + uart.baud(1200); + + uart.attach(&txCallback, MODSERIAL::TxIrq); + uart.attach(&rxCallback, MODSERIAL::RxIrq); + uart.attach(&txEmpty, MODSERIAL::TxEmpty); + + // Loop sending characters. We send 512 + // which is twice the default TX/RX buffer size. + + led1 = 1; // Show start of sending with LED1. + + for (int loop = 0; loop < 512; loop++) { + uart.printf("%c", c); + c++; + if (c > 'Z') c = 'A'; + } + + led1 = 0; // Show the end of sending by switching off LED1. + + // End program. Flash LED4. Notice how LED 2 and 3 continue + // to flash for a short period while the interrupt system + // continues to send the characters left in the TX buffer. + + while(1) { + led4 = !led4; + wait(0.25); + } +} + +/* + * Notes. Here is the sort of output you can expect on your PC/Mac/Linux host + * machine that is connected to the "pc" USB serial port. + * + * ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUV + * WXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQR + * STUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMN + * OPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJ + * KLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEF + * GHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZAB + * CDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQ Done. R + * + * Of interest is that last "R" character after the system has said "Done." + * This comes from the fact that the TxEmpty callback is made when the TX buffer + * becomes empty. MODSERIAL makes use of the fact that the Uarts built into the + * LPC17xx device use a 16 byte FIFO on both RX and TX channels. This means that + * when the TxEmpty callback is made, the TX buffer is empty, but that just means + * the "last few characters" were written to the TX FIFO. So although the TX + * buffer has gone empty, the Uart's transmit system is still sending any remaining + * characters from it's TX FIFO. If you want to be truely sure all the characters + * you have sent have left the Mbed then call txIsBusy(); This function will + * return true if characters are still being sent. If it returns false after + * the Tx buffer is empty then all your characters have been sent. + * + * In a similar way, when characters are received into the RX FIFO, the entire + * FIFO contents is moved to the RX buffer, assuming there is room left in the + * RX buffer. If there is not, any remaining characters are left in the RX FIFO + * and will be moved to the RX buffer on the next interrupt or when the running + * program removes a character(s) from the RX buffer with the getc() method. + */ + +#endif
diff -r 000000000000 -r 1447d2f773db MODSERIAL/example2.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MODSERIAL/example2.cpp Wed Jul 09 07:35:50 2014 +0000 @@ -0,0 +1,167 @@ +/* + Copyright (c) 2011 Andy Kirkham + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + + @file example2.cpp + @purpose Demos a simple messaging system. + @version see ChangeLog.c + @date Jan 2011 + @author Andy Kirkham +*/ + +/* + This example demostrates a simple "messaging" system. You can use it with + a terminal program to test it out or write a cusom C#/C++/VB/etc program + to read and write messages to or from the Mbed. The default baud rate in + this example is 115200. + + In this example, the LEDs are controlled and pins p21 to p24 are set as + InterruptIn and send messages out when their value changes. + + To use, hook up the MBed USB and open your fav terminal. All messages + end with the \n character, don't forget to hit carriage return!. + As an example:- + + to switch on LED1 send LED1:1\n, off is LED1:0\n and toggle is LED1:2\n + to switch on LED2 send LED2:1\n, off is LED2:0\n and toggle is LED2:2\n + to switch on LED3 send LED3:1\n, off is LED3:0\n and toggle is LED3:2\n + to switch on LED4 send LED4:1\n, off is LED4:0\n and toggle is LED4:2\n + + When a pin change on p21 to p24 happens, a message is sent. As an example + when p21 goes low PIN21:0\n is sent, when goes high PIN21:1\n is sent. + + Note, the InterruptIn pins p21 to p24 are setup to have pullups. This means + they are high. To activate them use a wire to short the pin to 0volts. + + If you find that p21 to p24 sent a lot of on/off/on/off then it's probably + due to "bounce". If you are connecting a mechanical switch to a pin you + may prefer to use the PinDetect library rather than using InterruptIn. + @see http://mbed.org/users/AjK/libraries/PinDetect/latest + + One point you may notice. Incoming messages are processed via main()'s + while(1) loop whereas pin changes have their messages directly sent. + The reason for this is when MODSERIAL makes callbacks to your application + it is in "interrupt context". And one thing you want to avoid is spending + lots of CPU time in that context. So, the callback moves the message from + the input buffer to a local holding buffer and it then sets a bool flag + which tells main()'s while(1) loop to process that buffer. This means the + time spent doing the real incoming message handing is within your program + and not within MODSERIAL's interrupt context. So you may ask, why not do + the same for out going messages? Well, because MODSERIAL output buffers + all your sent content then sending chars is very fast. MODSERIAL handles + all the nitty gritty bits for you. You can just send. This example uses + puts() to send the message. If you can, always try and use sprintf()+puts() + rathe than printf(), printf() is known to often screw things up when used + within an interrupt context. Better still, just use puts() and do away + with any of the crappy ?printf() calls if possible. But I found the code + below to work fine even at 115200baud. + +*/ + + +#ifdef COMPILE_EXAMPLE1_CODE_MODSERIAL + +#include "mbed.h" +#include "MODSERIAL.h" + +#define MESSAGE_BUFFER_SIZE 32 + +DigitalOut led1(LED1); +DigitalOut led2(LED2); +DigitalOut led3(LED3); +DigitalOut led4(LED4); + +InterruptIn P21(p21); +InterruptIn P22(p22); +InterruptIn P23(p23); +InterruptIn P24(p24); + +MODSERIAL messageSystem(USBTX, USBRX); + +char messageBufferIncoming[MESSAGE_BUFFER_SIZE]; +char messageBufferOutgoing[MESSAGE_BUFFER_SIZE]; +bool messageReceived; + +void messageReceive(MODSERIAL_IRQ_INFO *q) { + MODSERIAL *sys = q->serial; + sys->move(messageBufferIncoming, MESSAGE_BUFFER_SIZE); + messageReceived = true; + return 0; +} + +void messageProcess(void) { + if (!strncmp(messageBufferIncoming, "LED1:1", sizeof("LED1:1")-1)) led1 = 1; + else if (!strncmp(messageBufferIncoming, "LED1:0", sizeof("LED1:0")-1)) led1 = 0; + else if (!strncmp(messageBufferIncoming, "LED1:2", sizeof("LED1:2")-1)) led1 = !led1; + + else if (!strncmp(messageBufferIncoming, "LED2:1", sizeof("LED2:1")-1)) led2 = 1; + else if (!strncmp(messageBufferIncoming, "LED2:0", sizeof("LED2:0")-1)) led2 = 0; + else if (!strncmp(messageBufferIncoming, "LED2:2", sizeof("LED2:2")-1)) led2 = !led2; + + else if (!strncmp(messageBufferIncoming, "LED3:1", sizeof("LED3:1")-1)) led3 = 1; + else if (!strncmp(messageBufferIncoming, "LED3:0", sizeof("LED3:0")-1)) led3 = 0; + else if (!strncmp(messageBufferIncoming, "LED3:2", sizeof("LED3:2")-1)) led3 = !led3; + + else if (!strncmp(messageBufferIncoming, "LED4:1", sizeof("LED4:1")-1)) led4 = 1; + else if (!strncmp(messageBufferIncoming, "LED4:0", sizeof("LED4:0")-1)) led4 = 0; + else if (!strncmp(messageBufferIncoming, "LED4:2", sizeof("LED4:2")-1)) led4 = !led4; + + messageReceived = false; +} + +#define PIN_MESSAGE_SEND(x,y) \ + sprintf(messageBufferOutgoing,"PIN%02d:%d\n",x,y);\ + messageSystem.puts(messageBufferOutgoing); + +void pin21Rise(void) { PIN_MESSAGE_SEND(21, 1); } +void pin21Fall(void) { PIN_MESSAGE_SEND(21, 0); } +void pin22Rise(void) { PIN_MESSAGE_SEND(22, 1); } +void pin22Fall(void) { PIN_MESSAGE_SEND(22, 0); } +void pin23Rise(void) { PIN_MESSAGE_SEND(23, 1); } +void pin23Fall(void) { PIN_MESSAGE_SEND(23, 0); } +void pin24Rise(void) { PIN_MESSAGE_SEND(24, 1); } +void pin24Fall(void) { PIN_MESSAGE_SEND(24, 0); } + +int main() { + + messageReceived = false; + messageSystem.baud(115200); + messageSystem.attach(&messageReceive, MODSERIAL::RxAutoDetect); + messageSystem.autoDetectChar('\n'); + + // Enable pullup resistors on pins. + P21.mode(PullUp); P22.mode(PullUp); P23.mode(PullUp); P24.mode(PullUp); + + // Fix Mbed library bug, see http://mbed.org/forum/bugs-suggestions/topic/1498 + LPC_GPIOINT->IO2IntClr = (1UL << 5) | (1UL << 4) | (1UL << 3) | (1UL << 2); + + // Attach InterruptIn pin callbacks. + P21.rise(&pin21Rise); P21.fall(&pin21Fall); + P22.rise(&pin22Rise); P22.fall(&pin22Fall); + P23.rise(&pin23Rise); P23.fall(&pin23Fall); + P24.rise(&pin24Rise); P24.fall(&pin24Fall); + + while(1) { + // Process incoming messages. + if (messageReceived) messageProcess(); + } +} + +#endif
diff -r 000000000000 -r 1447d2f773db MODSERIAL/example3a.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MODSERIAL/example3a.cpp Wed Jul 09 07:35:50 2014 +0000 @@ -0,0 +1,83 @@ +/* + Copyright (c) 2011 Andy Kirkham + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + + @file example3.cpp + @purpose Demos a simple filter. + @version see ChangeLog.c + @author Andy Kirkham +*/ + +/* + This example shows how to use the new callback system. In the old system + Mbed's FunctionPointer[1] type was used to store abd make calls to callbacks. + However, that limits the callback function prototype to void func(void); + which means we cannot pass parameters. + + This latest version of MODSERIAL now uses its own callback object. This allows + the passing of a pointer to a class that holds information about the MODSERIAL + object making the callback. As of version 1.18 one critcal piece of information + is passed, a pointer to the MODSERIAL object. This allows callbacks to use the + MODSERIAL functions and data. + + Additionally, since MODSERIAL and the callback parameter class MODSERIAL_IRQ_INFO + are friends, MODSERIAL_IRQ_INFO can access the protected functions of MODSERIAL. + This is used to ensure functions that can only be called during a callback + can be invoked from a callback. + + [1] http://mbed.org/projects/libraries/svn/mbed/trunk/FunctionPointer.h +*/ + +#ifdef COMPILE_EXAMPLE3_CODE_MODSERIAL + +#include "mbed.h" +#include "MODSERIAL.h" + +DigitalOut led1(LED1); + +MODSERIAL pc(USBTX, USBRX); + +// The following callback is defined in example3b.cpp +//! @see example3b.cpp +void rxCallback(MODSERIAL_IRQ_INFO *info); + +int main() { + + int life_counter = 0; + + pc.baud(115200); + + pc.attach(&rxCallback, MODSERIAL::RxIrq); + + while(1) { + // Echo back any chars we get except 'A' which is filtered by the rxCallback. + if (pc.readable()) { + pc.putc(pc.getc()); + } + + // Toggle LED1 every so often to show we are alive. + if (life_counter++ == 1000000) { + life_counter = 0; + led1 = !led1; + } + } +} + +#endif
diff -r 000000000000 -r 1447d2f773db MODSERIAL/example3b.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MODSERIAL/example3b.cpp Wed Jul 09 07:35:50 2014 +0000 @@ -0,0 +1,78 @@ +/* + Copyright (c) 2011 Andy Kirkham + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + + @file example3b.cpp + @purpose Demos a simple filter. + @version see ChangeLog.c + @author Andy Kirkham +*/ + +/* + This example shows how to use the new callback system. In the old system + Mbed's FunctionPointer[1] type was used to store abd make calls to callbacks. + However, that limits the callback function prototype to void func(void); + which means we cannot pass parameters. + + This latest version of MODSERIAL now uses its own callback object. This allows + the passing of a pointer to a class that holds information about the MODSERIAL + object making the callback. As of version 1.18 one critcal piece of information + is passed, a pointer to the MODSERIAL object. This allows callbacks to use the + MODSERIAL functions and data. + + Additionally, since MODSERIAL and the callback parameter class MODSERIAL_IRQ_INFO + are friends, MODSERIAL_IRQ_INFO can access the protected functions of MODSERIAL. + This is used to ensure functions that can only be called during a callback + can be invoked from a callback. + + [1] http://mbed.org/projects/libraries/svn/mbed/trunk/FunctionPointer.h +*/ + + +#ifdef COMPILE_EXAMPLE3_CODE_MODSERIAL + +#include "mbed.h" +#include "MODSERIAL.h" + +void rxCallback(MODSERIAL_IRQ_INFO *info) { + + // Get the pointer to our MODSERIAL object that invoked this callback. + MODSERIAL *pc = info->serial; + + // info->serial points at the MODSERIAL instance so we can use it to call + // any of the public MODSERIAL functions that are normally available. So + // there's now no need to use the global version (pc in our case) inside + // callback functions. + char c = pc->rxGetLastChar(); // Where local pc variable is a pointer to the global MODSERIAL pc object. + + // The following is rather daft but demos the point. + // Don't allow the letter "A" go into the RX buffer. + // Basically acts as a filter to remove the letter "A" + // if it goes into the RX buffer. + if (c == 'A') { + // Note, we call the MODSERIAL_IRQ_INFO::rxDiscardLastChar() public function which + // is permitted access to the protected version of MODSERIAL::rxDiscardLastChar() + // within MODSERIAL (because they are friends). This ensures rxDiscardLastChar() + // can only be called within an rxCallback function. + info->rxDiscardLastChar(); + } +} + +#endif
diff -r 000000000000 -r 1447d2f773db MODSERIAL/example_dma.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MODSERIAL/example_dma.cpp Wed Jul 09 07:35:50 2014 +0000 @@ -0,0 +1,144 @@ +#ifdef COMPILE_EXAMPLE_CODE_MODSERIAL_MODDMA + +/* + * To run this test program, link p9 to p10 so the Serial loops + * back and receives characters it sends. + */ + +#include "mbed.h" + +/* Note, this example requires that you also import into the Mbed + compiler the MODDMA project as well as MODSERIAL + http://mbed.org/users/AjK/libraries/MODDMA/latest + MODDMA.h MUST come before MODSERIAL.h */ +#include "MODDMA.h" // <--- Declare first +#include "MODSERIAL.h" // Flollowed by MODSERIAL + +DigitalOut led1(LED1); +DigitalOut led2(LED2); +DigitalOut led3(LED3); +DigitalOut led4(LED4); + +MODSERIAL pc(USBTX, USBRX); + +/* + * As experiement, you can define MODSERIAL as show here and see what + * effects it has on the LEDs. + * + * MODSERIAL uart(TX_PIN, RX_PIN, 512); + * With this, the 512 characters sent can straight into the buffer + * vary quickly. This means LED1 is only on briefly as the TX buffer + * fills. + * + * MODSERIAL uart(TX_PIN, RX_PIN, 32); + * With this, the buffer is smaller than the default 256 bytes and + * therefore LED1 stays on much longer while the system waits for + * room in the TX buffer. + */ +MODSERIAL uart(TX_PIN, RX_PIN); + +MODDMA dma; + +// This function is called when a character goes from the TX buffer +// to the Uart THR FIFO register. +void txCallback(void) { + led2 = !led2; +} + +// This function is called when TX buffer goes empty +void txEmpty(void) { + led2 = 0; + pc.puts(" Done. "); +} + +void dmaComplete(void) { + led1 = 1; +} + +// This function is called when a character goes into the RX buffer. +void rxCallback(void) { + led3 = !led3; + pc.putc(uart.getc()); +} + +int main() { + char s1[] = " *DMA* *DMA* *DMA* *DMA* *DMA* *DMA* *DMA* "; + int c = 'A'; + + // Tell MODSERIAL where the MODDMA controller is. + pc.MODDMA( &dma ); + + // Ensure the baud rate for the PC "USB" serial is much + // higher than "uart" baud rate below. + pc.baud( PC_BAUD ); + + // Use a deliberatly slow baud to fill up the TX buffer + uart.baud(1200); + + uart.attach( &txCallback, MODSERIAL::TxIrq ); + uart.attach( &rxCallback, MODSERIAL::RxIrq ); + uart.attach( &txEmpty, MODSERIAL::TxEmpty ); + + // Loop sending characters. We send 512 + // which is twice the default TX/RX buffer size. + + led1 = 0; + + // Send the buffer s using DMA channel 7 + pc.attach_dmaSendComplete( &dmaComplete ); + pc.dmaSend( s1, sizeof(s1), MODDMA::Channel_7 ); + + for (int loop = 0; loop < 512; loop++) { + uart.printf("%c", c); + c++; + if (c > 'Z') c = 'A'; + } + + led1 = 0; // Show the end of sending by switching off LED1. + + // End program. Flash LED4. Notice how LED 2 and 3 continue + // to flash for a short period while the interrupt system + // continues to send the characters left in the TX buffer. + + while(1) { + led4 = !led4; + wait(0.25); + } +} + +/* + * Notes. Here is the sort of output you can expect on your PC/Mac/Linux host + * machine that is connected to the "pc" USB serial port. + * + * *DMA* *DMA* *DMA* *DMA* *DMA* *DMA* *DMA* ABCDEFGHIJKLMNOPQRSTUVWXYZABCDE + * FGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZA + * BCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVW + * XYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRS + * TUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNO + * PQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJK + * LMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFG + * HIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQ Done. R + * + * Note how the DMA blocks the TX buffer sending under standard interrupt control. + * Not until the DMA transfer is complete will "normal" buffered TX sending resume. + * + * Of interest is that last "R" character after the system has said "Done." + * This comes from the fact that the TxEmpty callback is made when the TX buffer + * becomes empty. MODSERIAL makes use of the fact that the Uarts built into the + * LPC17xx device use a 16 byte FIFO on both RX and TX channels. This means that + * when the TxEmpty callback is made, the TX buffer is empty, but that just means + * the "last few characters" were written to the TX FIFO. So although the TX + * buffer has gone empty, the Uart's transmit system is still sending any remaining + * characters from it's TX FIFO. If you want to be truely sure all the characters + * you have sent have left the Mbed then call txIsBusy(); This function will + * return true if characters are still being sent. If it returns false after + * the Tx buffer is empty then all your characters have been sent. + * + * In a similar way, when characters are received into the RX FIFO, the entire + * FIFO contents is moved to the RX buffer, assuming there is room left in the + * RX buffer. If there is not, any remaining characters are left in the RX FIFO + * and will be moved to the RX buffer on the next interrupt or when the running + * program removes a character(s) from the RX buffer with the getc() method. + */ + +#endif
diff -r 000000000000 -r 1447d2f773db UM6_config/UM6_config.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/UM6_config/UM6_config.h Wed Jul 09 07:35:50 2014 +0000 @@ -0,0 +1,479 @@ +/* ------------------------------------------------------------------------------ + File: UM6_config.h + Author: CH Robotics + Version: 1.0 + + Description: Preprocessor definitions and function declarations for UM6 configuration +------------------------------------------------------------------------------ */ +#ifndef __UM6_CONFIG_H +#define __UM6_CONFIG_H +#include "UM6_usart.h" + + +MODSERIAL um6_uart(p9, p10); // UM6 SERIAL OVER UART Pin 9 & Pin 10 + + + + + + + + +// CONFIG_ARRAY_SIZE and DATA_ARRAY_SIZE specify the number of 32 bit configuration and data registers used by the firmware +// (Note: The term "register" is used loosely here. These "registers" are not actually registers in the same sense of a +// microcontroller register. They are simply index locations into arrays stored in global memory. Data and configuration +// parameters are stored in arrays because it allows a common communication protocol to be used to access all data and +// configuration. The software communicating with the sensor needs only specify the register address, and the communication +// software running on the sensor knows exactly where to find it - it needn't know what the data is. The software communicatin +// with the sensor, on the other hand, needs to know what it is asking for (naturally...) +// This setup makes it easy to make more data immediately available when needed - simply increase the array size, add code in +// the firmware that writes data to the new array location, and then make updates to the firmware definition on the PC side. +#define CONFIG_ARRAY_SIZE 44 +#define DATA_ARRAY_SIZE 33 +#define COMMAND_COUNT 9 + +// +#define CONFIG_REG_START_ADDRESS 0 +#define DATA_REG_START_ADDRESS 85 +#define COMMAND_START_ADDRESS 170 + +// These preprocessor definitions make it easier to access specific configuration parameters in code +// They specify array locations associated with each register name. Note that in the comments below, many of the values are +// said to be 32-bit IEEE floating point. Obviously this isn't directly the case, since the arrays are actually 32-bit unsigned +// integer arrays. Bit for bit, the data does correspond to the correct floating point value. Since you can't cast ints as floats, +// special conversion has to happen to copy the float data to and from the array. +// Starting with configuration register locations... + + +// Now for data register locations. +// In the communication protocol, data registers are labeled with number ranging from 128 to 255. The value of 128 will be subtracted from these numbers +// to produce the actual array index labeled below +#define UM6_STATUS DATA_REG_START_ADDRESS // Status register defines error codes with individual bits +#define UM6_GYRO_RAW_XY (DATA_REG_START_ADDRESS + 1) // Raw gyro data is stored in 16-bit signed integers +#define UM6_GYRO_RAW_Z (DATA_REG_START_ADDRESS + 2) +#define UM6_ACCEL_RAW_XY (DATA_REG_START_ADDRESS + 3) // Raw accel data is stored in 16-bit signed integers +#define UM6_ACCEL_RAW_Z (DATA_REG_START_ADDRESS + 4) +#define UM6_MAG_RAW_XY (DATA_REG_START_ADDRESS + 5) // Raw mag data is stored in 16-bit signed integers +#define UM6_MAG_RAW_Z (DATA_REG_START_ADDRESS + 6) +#define UM6_GYRO_PROC_XY (DATA_REG_START_ADDRESS + 7) // Processed gyro data has scale factors applied and alignment correction performed. Data is 16-bit signed integer. +#define UM6_GYRO_PROC_Z (DATA_REG_START_ADDRESS + 8) +#define UM6_ACCEL_PROC_XY (DATA_REG_START_ADDRESS + 9) // Processed accel data has scale factors applied and alignment correction performed. Data is 16-bit signed integer. +#define UM6_ACCEL_PROC_Z (DATA_REG_START_ADDRESS + 10) +#define UM6_MAG_PROC_XY (DATA_REG_START_ADDRESS + 11) // Processed mag data has scale factors applied and alignment correction performed. Data is 16-bit signed integer. +#define UM6_MAG_PROC_Z (DATA_REG_START_ADDRESS + 12) +#define UM6_EULER_PHI_THETA (DATA_REG_START_ADDRESS + 13) // Euler angles are 32-bit IEEE floating point +#define UM6_EULER_PSI (DATA_REG_START_ADDRESS + 14) +#define UM6_QUAT_AB (DATA_REG_START_ADDRESS + 15) // Quaternions are 16-bit signed integers. +#define UM6_QUAT_CD (DATA_REG_START_ADDRESS + 16) +#define UM6_ERROR_COV_00 (DATA_REG_START_ADDRESS + 17) // Error covariance is a 4x4 matrix of 32-bit IEEE floating point values +#define UM6_ERROR_COV_01 (DATA_REG_START_ADDRESS + 18) +#define UM6_ERROR_COV_02 (DATA_REG_START_ADDRESS + 19) +#define UM6_ERROR_COV_03 (DATA_REG_START_ADDRESS + 20) +#define UM6_ERROR_COV_10 (DATA_REG_START_ADDRESS + 21) +#define UM6_ERROR_COV_11 (DATA_REG_START_ADDRESS + 22) +#define UM6_ERROR_COV_12 (DATA_REG_START_ADDRESS + 23) +#define UM6_ERROR_COV_13 (DATA_REG_START_ADDRESS + 24) +#define UM6_ERROR_COV_20 (DATA_REG_START_ADDRESS + 25) +#define UM6_ERROR_COV_21 (DATA_REG_START_ADDRESS + 26) +#define UM6_ERROR_COV_22 (DATA_REG_START_ADDRESS + 27) +#define UM6_ERROR_COV_23 (DATA_REG_START_ADDRESS + 28) +#define UM6_ERROR_COV_30 (DATA_REG_START_ADDRESS + 29) +#define UM6_ERROR_COV_31 (DATA_REG_START_ADDRESS + 30) +#define UM6_ERROR_COV_32 (DATA_REG_START_ADDRESS + 31) +#define UM6_ERROR_COV_33 (DATA_REG_START_ADDRESS + 32) + + + +#define UM6_GET_FW_VERSION COMMAND_START_ADDRESS // Causes the UM6 to report the firmware revision +#define UM6_FLASH_COMMIT (COMMAND_START_ADDRESS + 1) // Causes the UM6 to write all configuration values to FLASH +#define UM6_ZERO_GYROS (COMMAND_START_ADDRESS + 2) // Causes the UM6 to start a zero gyros command +#define UM6_RESET_EKF (COMMAND_START_ADDRESS + 3) // Causes the UM6 to reset the EKF +#define UM6_GET_DATA (COMMAND_START_ADDRESS + 4) // Causes the UM6 to transmit a data packet containing data from all enabled channels +#define UM6_SET_ACCEL_REF (COMMAND_START_ADDRESS + 5) // Causes the UM6 to set the current measured accel data to the reference vector +#define UM6_SET_MAG_REF (COMMAND_START_ADDRESS + 6) // Causes the UM6 to set the current measured magnetometer data to the reference vector +#define UM6_RESET_TO_FACTORY (COMMAND_START_ADDRESS + 7) // Causes the UM6 to load default factory settings + +#define UM6_SAVE_FACTORY (COMMAND_START_ADDRESS + 8) // Causes the UM6 to save the current settings to the factory flash location + +#define UM6_USE_CONFIG_ADDRESS 0 +#define UM6_USE_FACTORY_ADDRESS 1 + +#define UM6_BAD_CHECKSUM 253 // Sent if the UM6 receives a packet with a bad checksum +#define UM6_UNKNOWN_ADDRESS 254 // Sent if the UM6 receives a packet with an unknown address +#define UM6_INVALID_BATCH_SIZE 255 // Sent if a requested batch read or write operation would go beyond the bounds of the config or data array + + + + + + +/******************************************************************************* +* Function Name : ComputeChecksum +* Input : USARTPacket* new_packet +* Output : None +* Return : uint16_t +* Description : Returns the two byte sum of all the individual bytes in the + given packet. +*******************************************************************************/ +uint16_t ComputeChecksum( USARTPacket* new_packet ) { + int32_t index; + uint16_t checksum = 0x73 + 0x6E + 0x70 + new_packet->PT + new_packet->address; + + for ( index = 0; index < new_packet->data_length; index++ ) { + checksum += new_packet->packet_data[index]; + } + return checksum; +} + + + + + +static USARTPacket new_packet; + +// Flag for storing the current USART state +uint8_t gUSART_State = USART_STATE_WAIT; + + +struct UM6{ +float Gyro_Proc_X; +float Gyro_Proc_Y; +float Gyro_Proc_Z; +float Accel_Proc_X; +float Accel_Proc_Y; +float Accel_Proc_Z; +float Mag_Proc_X; +float Mag_Proc_Y; +float Mag_Proc_Z; +float Roll; +float Pitch; +float Yaw; +}; +UM6 data; + + + + +void Process_um6_packet() { + +int16_t MY_DATA_GYRO_PROC_X; +int16_t MY_DATA_GYRO_PROC_Y; +int16_t MY_DATA_GYRO_PROC_Z; +int16_t MY_DATA_ACCEL_PROC_X; +int16_t MY_DATA_ACCEL_PROC_Y; +int16_t MY_DATA_ACCEL_PROC_Z; +int16_t MY_DATA_MAG_PROC_X; +int16_t MY_DATA_MAG_PROC_Y; +int16_t MY_DATA_MAG_PROC_Z; +int16_t MY_DATA_EULER_PHI; +int16_t MY_DATA_EULER_THETA; +int16_t MY_DATA_EULER_PSI; + + + +static uint8_t data_counter = 0; + + + + // The next action should depend on the USART state. + switch ( gUSART_State ) { + // USART in the WAIT state. In this state, the USART is waiting to see the sequence of bytes + // that signals a new incoming packet. + case USART_STATE_WAIT: + if ( data_counter == 0 ) { // Waiting on 's' character + if ( um6_uart.getc() == 's' ) { + + data_counter++; + } else { + data_counter = 0; + } + } else if ( data_counter == 1 ) { // Waiting on 'n' character + if ( um6_uart.getc() == 'n' ) { + data_counter++; + + } else { + data_counter = 0; + } + } else if ( data_counter == 2 ) { // Waiting on 'p' character + if ( um6_uart.getc() == 'p' ) { + // The full 'snp' sequence was received. Reset data_counter (it will be used again + // later) and transition to the next state. + data_counter = 0; + gUSART_State = USART_STATE_TYPE; + + } else { + data_counter = 0; + } + } + break; + + // USART in the TYPE state. In this state, the USART has just received the sequence of bytes that + // indicates a new packet is about to arrive. Now, the USART expects to see the packet type. + case USART_STATE_TYPE: + + new_packet.PT = um6_uart.getc(); + + gUSART_State = USART_STATE_ADDRESS; + + break; + + // USART in the ADDRESS state. In this state, the USART expects to receive a single byte indicating + // the address that the packet applies to + case USART_STATE_ADDRESS: + new_packet.address = um6_uart.getc(); + + // For convenience, identify the type of packet this is and copy to the packet structure + // (this will be used by the packet handler later) + if ( (new_packet.address >= CONFIG_REG_START_ADDRESS) && (new_packet.address < DATA_REG_START_ADDRESS) ) { + new_packet.address_type = ADDRESS_TYPE_CONFIG; + } else if ( (new_packet.address >= DATA_REG_START_ADDRESS) && (new_packet.address < COMMAND_START_ADDRESS) ) { + new_packet.address_type = ADDRESS_TYPE_DATA; + } else { + new_packet.address_type = ADDRESS_TYPE_COMMAND; + } + + // Identify the type of communication this is (whether reading or writing to a data or configuration register, or sending a command) + // If this is a read operation, jump directly to the USART_STATE_CHECKSUM state - there is no more data in the packet + if ( (new_packet.PT & PACKET_HAS_DATA) == 0 ) { + gUSART_State = USART_STATE_CHECKSUM; + } + + // If this is a write operation, go to the USART_STATE_DATA state to read in the relevant data + else { + gUSART_State = USART_STATE_DATA; + // Determine the expected number of bytes in this data packet based on the packet type. A write operation + // consists of 4 bytes unless it is a batch operation, in which case the number of bytes equals 4*batch_size, + // where the batch size is also given in the packet type byte. + if ( new_packet.PT & PACKET_IS_BATCH ) { + new_packet.data_length = 4*((new_packet.PT >> 2) & PACKET_BATCH_LENGTH_MASK); + + } else { + new_packet.data_length = 4; + } + } + break; + + // USART in the DATA state. In this state, the USART expects to receive new_packet.length bytes of + // data. + case USART_STATE_DATA: + new_packet.packet_data[data_counter] = um6_uart.getc(); + data_counter++; + + // If the expected number of bytes has been received, transition to the CHECKSUM state. + if ( data_counter == new_packet.data_length ) { + // Reset data_counter, since it will be used in the CHECKSUM state. + data_counter = 0; + gUSART_State = USART_STATE_CHECKSUM; + } + break; + + + + // USART in CHECKSUM state. In this state, the entire packet has been received, with the exception + // of the 16-bit checksum. + case USART_STATE_CHECKSUM: + // Get the highest-order byte + if ( data_counter == 0 ) { + new_packet.checksum = ((uint16_t)um6_uart.getc() << 8); + data_counter++; + } else { // ( data_counter == 1 ) + // Get lower-order byte + new_packet.checksum = new_packet.checksum | ((uint16_t)um6_uart.getc() & 0x0FF); + + // Both checksum bytes have been received. Make sure that the checksum is valid. + uint16_t checksum = ComputeChecksum( &new_packet ); + + + + // If checksum does not match, exit function + if ( checksum != new_packet.checksum ) { + return; + } // end if(checksum check) + + + + else + + { + + // Packet was received correctly. + + //----------------------------------------------------------------------------------------------- + //----------------------------------------------------------------------------------------------- + // + // CHECKSUM WAS GOOD SO GET ARE DATA!!!!!!!!!!!! + + + // IF DATA ADDRESS + if (new_packet.address_type == ADDRESS_TYPE_DATA) { + + //------------------------------------------------------------ + // UM6_GYRO_PROC_XY (0x5C) + // To convert the register data from 16-bit 2's complement integers to actual angular rates in degrees + // per second, the data should be multiplied by the scale factor 0.0610352 as shown below + // angular_rate = register_data*0.0610352 + + if (new_packet.address == UM6_GYRO_PROC_XY) { + + // GYRO_PROC_X + MY_DATA_GYRO_PROC_X = (int16_t)new_packet.packet_data[0]<<8; //bitshift it + MY_DATA_GYRO_PROC_X |= new_packet.packet_data[1]; + data.Gyro_Proc_X = MY_DATA_GYRO_PROC_X*0.0610352; + + MY_DATA_GYRO_PROC_Y = (int16_t)new_packet.packet_data[2]<<8; //bitshift it + MY_DATA_GYRO_PROC_Y |= new_packet.packet_data[3]; + data.Gyro_Proc_Y = MY_DATA_GYRO_PROC_Y*0.0610352; + + + //------------------------------------------------------------ + + + //------------------------------------------------------------ + // UM6_GYRO_PROC_Z (0x5D) + // To convert the register data from a 16-bit 2's complement integer to the actual angular rate in + // degrees per second, the data should be multiplied by the scale factor 0.0610352 as shown below. + + + // GYRO_PROC_Z + MY_DATA_GYRO_PROC_Z = (int16_t)new_packet.packet_data[4]<<8; //bitshift it + MY_DATA_GYRO_PROC_Z |= new_packet.packet_data[5];; + data.Gyro_Proc_Z = MY_DATA_GYRO_PROC_Z*0.0610352; + + + } // end if(MY_DATA_GYRO_PROC) + //------------------------------------------------------------ + + + //------------------------------------------------------------ + // UM6_ACCEL_PROC_XY (0x5E) + // To convert the register data from 16-bit 2's complement integers to actual acceleration in gravities, + // the data should be multiplied by the scale factor 0.000183105 as shown below. + // acceleration = register_data* 0.000183105 + if (new_packet.address == UM6_ACCEL_PROC_XY) { + + // ACCEL_PROC_X + MY_DATA_ACCEL_PROC_X = (int16_t)new_packet.packet_data[0]<<8; //bitshift it + MY_DATA_ACCEL_PROC_X |= new_packet.packet_data[1]; + data.Accel_Proc_X = MY_DATA_ACCEL_PROC_X*0.000183105; + + // ACCEL_PROC_Y + MY_DATA_ACCEL_PROC_Y = (int16_t)new_packet.packet_data[2]<<8; //bitshift it + MY_DATA_ACCEL_PROC_Y |= new_packet.packet_data[3]; + data.Accel_Proc_Y = MY_DATA_ACCEL_PROC_Y*0.000183105; + + //------------------------------------------------------------ + + + //------------------------------------------------------------ + // UM6_ACCEL_PROC_Z (0x5F) + // To convert the register data from a 16-bit 2's complement integer to the actual acceleration in + // gravities, the data should be multiplied by the scale factor 0.000183105 as shown below. + + // ACCEL_PROC_Z + MY_DATA_ACCEL_PROC_Z = (int16_t)new_packet.packet_data[4]<<8; //bitshift it + MY_DATA_ACCEL_PROC_Z |= new_packet.packet_data[5]; + data.Accel_Proc_Z = MY_DATA_ACCEL_PROC_Z*0.000183105; + + } // end if(MY_DATA_ACCEL_PROC) + + //------------------------------------------------------------ + + + //------------------------------------------------------------ + // UM6_MAG_PROC_XY (0x60) + // To convert the register data from 16-bit 2's complement integers to a unit-norm (assuming proper + // calibration) magnetic-field vector, the data should be multiplied by the scale factor 0.000305176 as + // shown below. + // magnetic field = register_data* 0.000305176 + if (new_packet.address == UM6_MAG_PROC_XY) { + + // MAG_PROC_X + MY_DATA_MAG_PROC_X = (int16_t)new_packet.packet_data[0]<<8; //bitshift it + MY_DATA_MAG_PROC_X |= new_packet.packet_data[1]; + data.Mag_Proc_X = MY_DATA_MAG_PROC_X*0.000305176; + + + // MAG_PROC_Y + MY_DATA_MAG_PROC_Y = (int16_t)new_packet.packet_data[2]<<8; //bitshift it + MY_DATA_MAG_PROC_Y |= new_packet.packet_data[3]; + data.Mag_Proc_Y = MY_DATA_MAG_PROC_Y*0.000305176; + + //------------------------------------------------------------ + + + //------------------------------------------------------------ + // UM6_MAG_PROC_Z (0x61) + // To convert the register data from 16-bit 2's complement integers to a unit-norm (assuming proper + // calibration) magnetic-field vector, the data should be multiplied by the scale factor 0.000305176 as + // shown below. + // magnetic field = register_data*0.000305176 + + // MAG_PROC_Z + MY_DATA_MAG_PROC_Z = (int16_t)new_packet.packet_data[4]<<8; //bitshift it + MY_DATA_MAG_PROC_Z |= new_packet.packet_data[5]; + data.Mag_Proc_Z = MY_DATA_MAG_PROC_Z*0.000305176; + + } // end if(UM6_MAG_PROC) + //------------------------------------------------------------ + + + + //------------------------------------------------------------ + // UM6_EULER_PHI_THETA (0x62) + // Stores the most recently computed roll (phi) and pitch (theta) angle estimates. The angle + // estimates are stored as 16-bit 2's complement integers. To obtain the actual angle estimate in + // degrees, the register data should be multiplied by the scale factor 0.0109863 as shown below + // angle estimate = register_data* 0.0109863 + if (new_packet.address == UM6_EULER_PHI_THETA) { + // EULER_PHI (ROLL) + MY_DATA_EULER_PHI = (int16_t)new_packet.packet_data[0]<<8; //bitshift it + MY_DATA_EULER_PHI |= new_packet.packet_data[1]; + data.Roll = MY_DATA_EULER_PHI*0.0109863; + + + + + + // EULER_THETA (PITCH) + MY_DATA_EULER_THETA = (int16_t)new_packet.packet_data[2]<<8; //bitshift it + MY_DATA_EULER_THETA |= new_packet.packet_data[3]; + data.Pitch = MY_DATA_EULER_THETA*0.0109863; + + //------------------------------------------------------------ + + //------------------------------------------------------------ + // UM6_EULER_PSI (0x63) (YAW) + // Stores the most recently computed yaw (psi) angle estimate. The angle estimate is stored as a 16- + // bit 2's complement integer. To obtain the actual angle estimate in degrees, the register data + // should be multiplied by the scale factor 0.0109863 as shown below + + MY_DATA_EULER_PSI = (int16_t)new_packet.packet_data[4]<<8; //bitshift it + MY_DATA_EULER_PSI |= new_packet.packet_data[5]; + data.Yaw = MY_DATA_EULER_PSI*0.0109863; + + + } // end if(UM6_EULER_PHI_THETA) + //------------------------------------------------------------ + + } // end if(ADDRESS_TYPE_DATA) + + + // A full packet has been received. + // Put the USART back into the WAIT state and reset + // the data_counter variable so that it can be used to receive the next packet. + data_counter = 0; + gUSART_State = USART_STATE_WAIT; + + + } // end else(GET_DATA) + + } + break; + + } // end switch ( gUSART_State ) + +return; + + } // end get_gyro_x() + +#endif \ No newline at end of file
diff -r 000000000000 -r 1447d2f773db UM6_usart/UM6_usart.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/UM6_usart/UM6_usart.h Wed Jul 09 07:35:50 2014 +0000 @@ -0,0 +1,60 @@ +/* ______________________________________________________________________________________ + File: UM6_usart.h + Author: CH Robotics, adapted for mbed by lhiggs + Version: 1.0 + + Description: Function declarations for USART communucation + -------------------------------------------------------------------------------------- */ + + #ifndef _CHR_USART_H + #define _CHR_USART_H + + #define MAX_PACKET_DATA 40 + + // Definitions of states for USART receiver state machine (for receiving packets) + #define USART_STATE_WAIT 1 + #define USART_STATE_TYPE 2 + #define USART_STATE_ADDRESS 3 + #define USART_STATE_DATA 4 + #define USART_STATE_CHECKSUM 5 + + // Flags for interpreting the packet type byte in communication packets + #define PACKET_HAS_DATA (1 << 7) + #define PACKET_IS_BATCH (1 << 6) + #define PACKET_BATCH_LENGTH_MASK ( 0x0F ) + + #define PACKET_BATCH_LENGTH_OFFSET 2 + + #define BATCH_SIZE_2 2 + #define BATCH_SIZE_3 3 + + #define PACKET_NO_DATA 0 + #define PACKET_COMMAND_FAILED (1 << 0) + + + // Define flags for identifying the type of packet address received + #define ADDRESS_TYPE_CONFIG 0 + #define ADDRESS_TYPE_DATA 1 + #define ADDRESS_TYPE_COMMAND 2 + + +extern uint8_t gUSART_State; + + // Structure for storing TX and RX packet data + typedef struct _USARTPacket + { + uint8_t PT; // Packet type + uint8_t address; // Packet address + uint16_t checksum; // Checksum + + // Data included for convenience, but that isn't stored in the packet itself + uint8_t data_length; // Number of bytes in data section + uint8_t address_type; // Specified the address type (DATA, CONFIG, OR COMMAND) + + uint8_t packet_data[MAX_PACKET_DATA]; + + } USARTPacket; + +uint16_t ComputeChecksum( USARTPacket* new_packet ); + +#endif \ No newline at end of file
diff -r 000000000000 -r 1447d2f773db main.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main.cpp Wed Jul 09 07:35:50 2014 +0000 @@ -0,0 +1,661 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////////// +// Programm zu Lageregelung der Testplattform mit Hilfe von Reaktionskreiseln. +// Mit UM6-LT IMU als Trägheitsplattform, XBee-Funkmodul zum seriellen Datenübertraggung und mbed +// Mikrokontroller als Regelungs- und Stuerungscomputer. +// Im Programm sind ein PID- und ein PD-Regler implementiert. +// +// Datum: 10.01.2014 Autor: Grübel Dimitri +// +/////////////////////////////////////////////////////////////////////////////////////////////////// + + +#include "mbed.h" // MBED HEADER +#include "MODSERIAL.h" // MBED BUFFERED SERIAL HEADER +#include "UM6_usart.h" // UM6 USART HEADER +#include "UM6_config.h" // UM6 CONFIG HEADER + + // KOMMUNIKATIONSART MIT MBED: USB/XBEE +Serial ios(p28, p27); // Serielle Verbi. mit XBee über Pin: tx-28, rx-27 +//Serial ios(USBTX, USBRX); // Serielle Verbi. über USB Port vom PC + +DigitalOut rst(p11); // Digital Reset für the XBee, 200ns für reset +PwmOut x_kreisel(p21); // Pin21-PwmOut ist für Drehung um X-Achse +PwmOut y_kreisel(p23); // Pin23-PwmOut ist für Drehung um Y-Achse +PwmOut z_kreisel(p22); // Pin22-PwmOut ist für Drehung um Z-Achse + + // HIER WIRD PWM EINGESTELLT: +const float pulsweite = 10.0; // Pulsweite des Steuersignals in ms +const float pwwork = 2.0; // Pulsweite des Arbeitssignals in ms +const float startpw = 0.8; // Startpulsweite in ms +const float pwmfakt = (pwwork - startpw)/200.0; // Pulsweite pro 1% Leistung +const float max_leistung = 75.0; // Leistungsbegrenzung global in % +const float min_leistung = 10.0; // Notwendige Mindestleistung des Motors in % + +const float x_kp_min = 0.0; // min/max - Variablen kp für X/Y/Z-Achse +const float x_kp_max = 3.0; +const float y_kp_min = 0.0; +const float y_kp_max = 3.0; +const float z_kp_min = 0.0; +const float z_kp_max = 3.0; + +const float x_kd_min = 0.0; // min/max - Variablen kd für X/Y/Z-Achse +const float x_kd_max = 3.0; +const float y_kd_min = 0.0; +const float y_kd_max = 3.0; +const float z_kd_min = 0.0; +const float z_kd_max = 3.0; + +const float x_ki_min = 0.0; // min/max - Variablen ki für X/Y/Z-Achse +const float x_ki_max = 0.5; +const float y_ki_min = 0.0; +const float y_ki_max = 0.5; +const float z_ki_min = 0.0; +const float z_ki_max = 0.5; + +const float x_winkel_min = -45.0; // Winkelbegrenzung für X/Y/Z-Achse +const float x_winkel_max = 45.0; +const float y_winkel_min = -45.0; +const float y_winkel_max = 45.0; +const float z_winkel_min = -90.0; +const float z_winkel_max = 90.0; + +const float regelgenauigkeit = 1.5; // Regelgenauigkeit in Grad + +const float x_kp_def = 1.0; // DEFAULT REGELPARAMETER FÜR X/Y/Z-ACHSE +const float x_kd_def = 0.4; +const float x_ki_def = 0.01; +const float y_kp_def = 1.0; +const float y_kd_def = 0.4; +const float y_ki_def = 0.01; +const float z_kp_def = 1.0; +const float z_kd_def = 0.4; +const float z_ki_def = 0.01; + +DigitalOut uart_activity(LED1); // LED1 = UM6 SERIAL für Kommunikation + + +/// FUNKTIONEN //////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////////// + + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// rxCallback // FUNKTION FÜR INTERRUPT - ABFRAGE DER DATEN DIE UM6-LT SENDET + +void rxCallback(MODSERIAL_IRQ_INFO *q) +{ + if (um6_uart.rxBufferGetCount() >= MAX_PACKET_DATA) + { + uart_activity = !uart_activity; // LED leuchtet wenn RxBuff hat > 40 Bytes + Process_um6_packet(); + } +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// calcStellwert // FUNKTION ZUR STELLWERTBERECHNUNG FÜR MBED-PWM + +float calcStellwert(float leistung) +{ + return (startpw + ((leistung + 100) * pwmfakt)) / pulsweite; +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// print_gyro_data // FUNKTION ZUR AUSGABE DER AKTUELLEN WINKEL UND WINKELGESCHWINDIGKEITEN + +void print_gyro_data() +{ + ios.printf("Gyro_Proc_X %+6.1f deg/s\n", data.Gyro_Proc_X); + ios.printf("Gyro_Proc_Y %+6.1f deg/s\n", data.Gyro_Proc_Y); + ios.printf("Gyro_Proc_Z %+6.1f deg/s\n", data.Gyro_Proc_Z); + ios.printf("Roll %+6.1f deg\n", data.Roll); + ios.printf("Pitch %+6.1f deg\n", data.Pitch); + ios.printf("Yaw %+6.1f deg\n\n", data.Yaw); +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// print_gyro_angles // FUNKTION ZUR AUSGABE DER AKTUELLEN WINKEL + +void print_gyro_angles() +{ + ios.printf("Roll %+6.1f deg\n", data.Roll); + ios.printf("Pitch %+6.1f deg\n", data.Pitch); + ios.printf("Yaw %+6.1f deg\n\n", data.Yaw); +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// LageregelungAchse // FUNKTION ZUR LAGEREGELUNG FÜR EINE ACHSE - STATISCH - PD Regler + +void LageregelungAchse(float kp, float kd, float winkel, const float& gyro_veloc, + const float& gyro_angle, PwmOut& kreisel) +{ + float start_angle = gyro_angle; + float winkel_soll = gyro_angle + winkel; + float abweichung = gyro_angle - winkel_soll; + float leistung_alt = 0; // Variablen für Bremsverfahren + bool start = true; + + while (fabs(abweichung) > regelgenauigkeit) + { + float leistung = abweichung * kp - gyro_veloc * kd; + if (leistung > max_leistung) leistung = max_leistung; + if (leistung < -max_leistung) leistung = -max_leistung; + if (leistung > -min_leistung && leistung < -0.001) leistung = -min_leistung; + if (leistung < min_leistung && leistung > 0.001) leistung = min_leistung; + + int Bremsrichtung = 0; // Vorzeichenbestimmung der Abbremsrichtung + + if (leistung >= 0) + Bremsrichtung = -1; + else + Bremsrichtung = 1; + + float Stellwert = calcStellwert(leistung); // Berechnung Stellwert + kreisel.write(Stellwert); // Befehl an Motorregler über PWM + wait_ms(20); + abweichung = gyro_angle - winkel_soll; // Kontrolle der Regelgenauigkeit + + if (start == true) + { + leistung_alt = leistung; + start = false; + } + else + { + if (fabs(winkel) > 5.0) + { + if ( fabs(leistung) > min_leistung) + { + float delta_leistung = fabs(leistung) - fabs(leistung_alt); // Bestimmung Abfall Delta + if (delta_leistung < -0.001) + { // Abbremsung des Motors bei Leistungsabnahme + kreisel.write(calcStellwert(Bremsrichtung * min_leistung)); + wait_ms(10); + } + } + } + + leistung_alt = leistung; + } // Ende des Bremsverfahrens + + if (fabs(abweichung) <= regelgenauigkeit) + { // Vorzeichen für Bremsung wird bestimmt + print_gyro_data(); // Funktionsaufruf Gyrodaten ausgeben + kreisel.write(calcStellwert(Bremsrichtung * 100)); // Vollbremsung + wait_ms(650); + kreisel.write(calcStellwert(0)); // Motor aus + } + } + + float end_angle = gyro_angle; + ios.printf("Plattform wurde gedreht um %+6.1f deg\n\n", end_angle - start_angle); +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// LageregelungAchseDyn // FUNKTION ZUR LAGEREGELUNG FÜR EINE ACHSE - DYNAMISCH - PID Regler + +void LageregelungAchseDyn(float kp, float kd, float ki, float winkel, const float& gyro_veloc, + const float& gyro_angle, PwmOut& kreisel, float& dyn_leistung_leerlauf) +{ + + ios.printf("Start LageregelungAchseDyn\n"); + float start_angle = gyro_angle; + float winkel_soll = gyro_angle + winkel; + float abweichung = gyro_angle - winkel_soll; + float abweichung_sum = abweichung; + float leistung_alt = dyn_leistung_leerlauf; + bool start = true; + float leistung = 0.0; + float i_glied = 0.0; + + int cnt = 0; + while (fabs(abweichung) > regelgenauigkeit) + { + cnt += 1; + i_glied = abweichung_sum * 0.001 * ki; + ios.printf("%f\n", i_glied); + if (i_glied > 0.5) i_glied = 0.5; // I-Glied Limiter + if (i_glied < -0.5) i_glied = -0.5; + // Sumierstelle (PID Glieder) + leistung = dyn_leistung_leerlauf + abweichung * kp - gyro_veloc * kd + i_glied; + if (leistung > max_leistung) leistung = max_leistung; + if (leistung < min_leistung) leistung = min_leistung; + int Bremsrichtung = -1; // Vorzeichen der Abbremsrichtung + + float Stellwert = calcStellwert(leistung); // Berechnung Stellwert + kreisel.write(Stellwert); // Befehl an Motorregler über Pwm + wait_ms(10); + + if (start == true) + { + leistung_alt = leistung; + start = false; + } + /*else + { + if (leistung > min_leistung) + { + float delta_leistung = leistung - leistung_alt; // Bestimmung Abfall Delta + + // bei Abnahme der Leistung - Motor abbremsen + if (delta_leistung < -0.0001) + { + kreisel.write(calcStellwert(Bremsrichtung * min_leistung)); + wait_ms(5); + } + } + } + */ + leistung_alt = leistung; + abweichung = gyro_angle - winkel_soll; + abweichung_sum += abweichung; + } + + dyn_leistung_leerlauf = leistung - i_glied; + if (dyn_leistung_leerlauf < min_leistung) dyn_leistung_leerlauf = min_leistung; + if (dyn_leistung_leerlauf > max_leistung) dyn_leistung_leerlauf = max_leistung; + ios.printf("Leerlaufleistung: %f\n", dyn_leistung_leerlauf); + float end_angle = gyro_angle; + ios.printf("Plattform wurde gedreht um %+6.1f deg\n\n", end_angle - start_angle); + // Counter für durchlaufene Regelzyklen + ios.printf("\nEnde LageregelungAchseDyn; Counter: %i\n\n", cnt); +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// main // Hauptprogramm + +int main() +{ + ios.baud(115200); // Baudrate XBee Funkmodul + um6_uart.baud(115200); // Baudrate UM6-lt + um6_uart.attach(&rxCallback, MODSERIAL::RxIrq); // Interrupt Funktion für UART + + rst = 1; // Reset-Pin von XBee auf ON + + ios.printf("\nBitte warten, Startvorgang der Plattform...\n\n"); // Start-UP Prozedur + um6_uart.putc(0xAC); // Nulliert die Rate-Gyros + wait_ms(3500); + um6_uart.putc(0xAC); // Nulliert die Rate-Gyros + wait_ms(3500); + um6_uart.putc(0xAC); // Nulliert die Rate-Gyros + wait_ms(3500); + + x_kreisel.period_ms(pulsweite); + y_kreisel.period_ms(pulsweite); + z_kreisel.period_ms(pulsweite); + + ios.printf("\n\nTESTPLATTFORM ZUR SATELLITENLAGEREGELUNG MIT REAKTIONSKREISELN:\n\n"); + + int choice1 = 0; + + do + { + do + { + ios.printf("\n\nBitte folgende Anweisungen ausfuehren,falls nicht bereits erfolgt!\n" + "Stromversorgung der Testplattform trennen und ohne Druckluft mit X-Achse auf mag." + " Norden ausrichten.\n" + "Testplattform mit Wasserwaage horizontal tarieren.\n" + "Danach Stromversorgung herstellen und mbed Reset-Taste betaetigen.\n\n"); + + x_kreisel.write(calcStellwert(0)); //Initialisierung X-Motorrelger + y_kreisel.write(calcStellwert(0)); //Initialisierung Y-Motorrelger + z_kreisel.write(calcStellwert(0)); //Initialisierung Z-Motorrelger + + ios.printf("Menueauswahl:\n"); + ios.printf("\t1 - Testplattform um einzelne Achsen drehen\n"); + ios.printf("\t2 - Testplattform um drei Achsen drehen\n"); + ios.printf("\t3 - Lage der Testplattform aktiv regeln fuer dynamische Fehler\n"); + ios.printf("\t4 - Gyrodaten ausgeben [Winkel/Winkelgeschwindigkeiten]\n"); + ios.printf("\t5 - Programm beenden\n"); + ios.printf("\nEingabe >"); + ios.scanf("%i", &choice1); + }while (choice1 < 1 || choice1 > 5); + + if (choice1 == 1) + { + ios.printf("\nTestplattform ist initialisiert.\n\n"); + print_gyro_angles(); // Funktionsaufruf Gyrodwinkel ausgeben + float x_kp = x_kp_def; + float x_kd = x_kd_def; + float x_winkel = 0.0; + float y_kp = y_kp_def; + float y_kd = y_kd_def; + float y_winkel = 0.0; + float z_kp = z_kp_def; + float z_kd = z_kd_def; + float z_winkel = 0.0; + + int choice2 = 0; + + do + { + do + { + ios.printf("\n\nLAGEREGELUNG EINZELNER ACHSEN:\n\n"); + ios.printf("Menueauswahl:\n"); + ios.printf("\t1 - Satellitenplattform rollen (um X-Achse drehen)\n"); + ios.printf("\t2 - Satellitenplattform nicken (um Y-Achse drehen)\n"); + ios.printf("\t3 - Satellitenplattform gieren (um Z-Achse drehen)\n"); + ios.printf("\t4 - Auswahl abbrechen (esc).\n"); + ios.printf("\nEingabe >"); + ios.scanf("%i", &choice2); + }while (choice2 < 1 || choice2 > 4); + + if (choice2 == 1) + { + ios.printf("\n Reglerparameter kp eingeben [0 - +3] >"); + ios.scanf("%f", &x_kp); + if (x_kp > x_kp_max) x_kp = x_kp_max; // Begrenzung X-Achse kp Pos. + if (x_kp < x_kp_min) x_kp = x_kp_min; // Begrenzung X-Achse kp Neg. + ios.printf("\n Reglerparameter kd eingeben [0 - +3] >"); + ios.scanf("%f", &x_kd); + if (x_kd > x_kd_max) x_kd = x_kd_max; // Begrenzung X-Achse kd Pos. + if (x_kd < x_kd_min) x_kd = x_kd_min; // Begrenzung X-Achse kd Neg. + ios.printf("\n Rollwinkel Phi eingeben [-45 - +45] >"); + ios.scanf("%f", &x_winkel); + if (x_winkel > x_winkel_max) x_winkel = x_winkel_max; // Begrenzung X-Achse Winkel Pos. + if (x_winkel < x_winkel_min) x_winkel = x_winkel_min; // Begrenzung X-Achse Winkel Neg. + if (fabs(x_winkel) < regelgenauigkeit) ios.printf("\nRegelung ist nicht notwendig!"); + ios.printf("\nParameter kp = %f, Parameter kd = %f, Rollwinkel = %f\n", + x_kp, x_kd, x_winkel); + print_gyro_angles(); + LageregelungAchse(x_kp, x_kd, x_winkel, data.Gyro_Proc_X, data.Roll, x_kreisel); + } + else if (choice2 == 2) + { + ios.printf("\n Reglerparameter kp eingeben [0 - +3] >"); + ios.scanf("%f", &y_kp); + if (y_kp > y_kp_max) y_kp = y_kp_max; // Begrenzung Y-Achse kp Pos. + if (y_kp < y_kp_min) y_kp = y_kp_min; // Begrenzung Y-Achse kp Neg. + ios.printf("\n Reglerparameter kd eingeben [0 - +3] >"); + ios.scanf("%f", &y_kd); + if (y_kd > y_kd_max) y_kd = y_kd_max; // Begrenzung Y-Achse kd Pos. + if (y_kd < y_kd_min) y_kd = y_kd_min; // Begrenzung Y-Achse kd Neg. + ios.printf("\n Nickwinkel Theta eingeben [-45 - +45] >"); + ios.scanf("%f", &y_winkel); + if (y_winkel > y_winkel_max) y_winkel = y_winkel_max; // Begrenzung Y-Achse Winkel Pos. + if (y_winkel < y_winkel_min) y_winkel = y_winkel_min; // Begrenzung Y-Achse Winkel Neg. + if (fabs(y_winkel) < regelgenauigkeit) ios.printf("\nRegelung ist nicht notwendig!"); + ios.printf("\nParameter kp = %f, Parameter kd = %f, Nickwinkel = %f\n", + y_kp, y_kd, y_winkel); + print_gyro_angles(); + LageregelungAchse(y_kp, y_kd, y_winkel, data.Gyro_Proc_Y, data.Pitch, y_kreisel); + + } + else if (choice2 == 3) + { + ios.printf("\n Reglerparameter kp eingeben [0 - +3] >"); + ios.scanf("%f", &z_kp); + if (z_kp > z_kp_max) z_kp = z_kp_max; // Begrenzung Z-Achse kp Pos. + if (z_kp < z_kp_min) z_kp = z_kp_min; // Begrenzung Z-Achse kp Neg. + ios.printf("\n Reglerparameter kd eingeben [0 - +3] >"); + ios.scanf("%f", &z_kd); + if (z_kd > z_kd_max) z_kd = z_kd_max; // Begrenzung Z-Achse kd Pos. + if (z_kd < z_kd_min) z_kd = z_kd_min; // Begrenzung Z-Achse kd Neg. + ios.printf("\n Gierwinkel Psi eingeben [-90 - +90] >"); + ios.scanf("%f", &z_winkel); + if (z_winkel > z_winkel_max) z_winkel = z_winkel_max; // Begrenzung Z-Achse Winkel Pos. + if (z_winkel < z_winkel_min) z_winkel = z_winkel_min; // Begrenzung Z-Achse Winkel Neg. + if (fabs(z_winkel) < regelgenauigkeit) ios.printf("\nRegelung ist nicht notwendig!"); + ios.printf("\nParameter kp = %f, Parameter kd = %f, Gierwinkel = %f\n", + z_kp, z_kd, z_winkel); + print_gyro_angles(); + LageregelungAchse(z_kp, z_kd, z_winkel, data.Gyro_Proc_Z, data.Yaw, z_kreisel); + } + }while(choice2 != 4); + + } + else if (choice1 == 2) + { + float x_kp = x_kp_def; + float x_kd = x_kd_def; + float x_winkel = 0.0; + float y_kp = y_kp_def; + float y_kd = y_kd_def; + float y_winkel = 0.0; + float z_kp = z_kp_def; + float z_kd = z_kd_def; + float z_winkel = 0.0; + + int choice3 = 0; + + do + { + do + { + ios.printf("\n\nLAGEREGELUNG ALLER ACHSEN:\n\n"); + ios.printf("Bitte Plattform in gewuenschte Ausgangsposition bringen.\n"); + ios.printf("Plattform wird in Z-Y-X Reihenfolge gedreht!\n\n"); + ios.printf("Aktuelle Werte fuer Regler X-Achse: kp = %f kd = %f\n\n", x_kp, x_kd); + ios.printf("Aktuelle Werte fuer Regler Y-Achse: kp = %f kd = %f\n\n", y_kp, y_kd); + ios.printf("Aktuelle Werte fuer Regler Z-Achse: kp = %f kd = %f\n\n", z_kp, z_kd); + ios.printf("Menueauswahl:\n"); + ios.printf("\t1 - Regelparameter aendern?\n"); + ios.printf("\t2 - Plattform drehen-Winkel eingeben\n"); + ios.printf("\t3 - Auswahl abbrechen (esc).\n"); + ios.printf("\nEingabe >"); + ios.scanf("%i", &choice3); + }while (choice3 < 1 || choice3 > 3); + + if (choice3 == 1) + { + ios.printf("\n Reglerparameter x_kp eingeben [0 - +3] >"); + ios.scanf("%f", &x_kp); + if (x_kp > x_kp_max) x_kp = x_kp_max; // Begrenzung X-Achse kp Pos. + if (x_kp < x_kp_min) x_kp = x_kp_min; // Begrenzung X-Achse kp Neg. + ios.printf("\n Reglerparameter x_kd eingeben [0 - +3] >"); + ios.scanf("%f", &x_kd); + if (x_kd > x_kd_max) x_kd = x_kd_max; // Begrenzung X-Achse kd Pos. + if (x_kd < x_kd_min) x_kd = x_kd_min; // Begrenzung X-Achse kd Neg. + ios.printf("\n Reglerparameter y_kp eingeben [0 - +3] >"); + ios.scanf("%f", &y_kp); + if (y_kp > y_kp_max) y_kp = y_kp_max; // Begrenzung Y-Achse kp Pos. + if (y_kp < y_kp_min) y_kp = y_kp_min; // Begrenzung Y-Achse kp Neg. + ios.printf("\n Reglerparameter y_kd eingeben [0 - +3] >"); + ios.scanf("%f", &y_kd); + if (y_kd > y_kd_max) y_kd = y_kd_max; // Begrenzung Y-Achse kd Pos. + if (y_kd < y_kd_min) y_kd = y_kd_min; // Begrenzung Y-Achse kd Neg. + ios.printf("\n Reglerparameter z_kp eingeben [0 - +3] >"); + ios.scanf("%f", &z_kp); + if (z_kp > z_kp_max) z_kp = z_kp_max; // Begrenzung Z-Achse kp Pos. + if (z_kp < z_kp_min) z_kp = z_kp_min; // Begrenzung Z-Achse kp Neg. + ios.printf("\n Reglerparameter z_kd eingeben [0 - +3] >"); + ios.scanf("%f", &z_kd); + if (z_kd > z_kd_max) z_kd = z_kd_max; // Begrenzung Z-Achse kd Pos. + if (z_kd < z_kd_min) z_kd = z_kd_min; // Begrenzung Z-Achse kd Neg. + ios.printf("\n\n"); + ios.printf("Aktuelle Werte fuer Regler X-Achse: kp = %f kd = %f\n\n", x_kp, x_kd); + ios.printf("Aktuelle Werte fuer Regler Y-Achse: kp = %f kd = %f\n\n", y_kp, y_kd); + ios.printf("Aktuelle Werte fuer Regler Z-Achse: kp = %f kd = %f\n\n", z_kp, z_kd); + } + else if (choice3 == 2) + { // Eingabe der Drehwinkel + ios.printf("\n Gierwinkel Psi eingeben [-90 - +90] >"); + ios.scanf("%f", &z_winkel); + if (z_winkel > z_winkel_max) z_winkel = z_winkel_max; // Begrenzung Z-Achse Winkel Pos. + if (z_winkel < z_winkel_min) z_winkel = z_winkel_min; // Begrenzung Z-Achse Winkel Neg. + ios.printf("\n Nickwinkel Theta eingeben [-45 - +45] >"); + ios.scanf("%f", &y_winkel); + if (y_winkel > y_winkel_max) y_winkel = y_winkel_max; // Begrenzung Y-Achse Winkel Pos. + if (y_winkel < y_winkel_min) y_winkel = y_winkel_min; // Begrenzung Y-Achse Winkel Neg. + ios.printf("\n Rollwinkel Phi eingeben [-45 - +45] >"); + ios.scanf("%f", &x_winkel); + if (x_winkel > x_winkel_max) x_winkel = x_winkel_max; // Begrenzung X-Achse Winkel Pos. + if (x_winkel < x_winkel_min) x_winkel = x_winkel_min; // Begrenzung X-Achse Winkel Neg. + + if (fabs(z_winkel) < regelgenauigkeit && + fabs(y_winkel) < regelgenauigkeit && + fabs(x_winkel) < regelgenauigkeit) + { + ios.printf("\nRegelung ist nicht notwendig!"); + } + else + { + print_gyro_angles(); + LageregelungAchse(z_kp, z_kd, z_winkel, data.Gyro_Proc_Z, data.Yaw, z_kreisel); + wait_ms(250); + LageregelungAchse(y_kp, y_kd, y_winkel, data.Gyro_Proc_Y, data.Pitch, y_kreisel); + wait_ms(250); + LageregelungAchse(x_kp, x_kd, x_winkel, data.Gyro_Proc_X, data.Roll, x_kreisel); + print_gyro_angles(); + ios.printf("\n\nSoll die Plattform wieder in ihre Ausgangslage gefahren werden? " + "ja/nein\n"); + char yes_no[50]; + ios.scanf("%s", yes_no); + + if (strcmp(yes_no, "ja") == 0) // Plattform in auf Ausgangsposition drehen + { + LageregelungAchse(x_kp, x_kd, -x_winkel, data.Gyro_Proc_X, data.Roll, x_kreisel); + wait_ms(250); + LageregelungAchse(y_kp, y_kd, -y_winkel, data.Gyro_Proc_Y, data.Pitch, y_kreisel); + wait_ms(250); + LageregelungAchse(z_kp, z_kd, -z_winkel, data.Gyro_Proc_Z, data.Yaw, z_kreisel); + print_gyro_angles(); + } + } + } + + }while(choice3 != 3); + } + else if (choice1 == 3) + { + float x_kp = x_kp_def; + float x_kd = x_kd_def; + float x_ki = x_ki_def; + float y_kp = y_kp_def; + float y_kd = y_kd_def; + float y_ki = y_ki_def; + float z_kp = z_kp_def; + float z_kd = z_kd_def; + float z_ki = z_ki_def; + + int choice4 = 0; + + do + { + do + { + ios.printf("\n\nLage der Testplattform aktiv regeln fuer dynamische Fehler" + " (Position halten):\n\n"); + ios.printf("\n\nBitte Plattform in gewuenschte Ausgangsposition bringen und halten " + "bis die Kreisel " + "ihre Leerlaufdrehzahl erreicht haben.\n\n"); + ios.printf("Aktuelle Werte fuer Regler X-Achse: kp = %f kd = %f ki = %f\n", + x_kp, x_kd, x_ki); + ios.printf("Aktuelle Werte fuer Regler Y-Achse: kp = %f kd = %f ki = %f\n", + y_kp, y_kd, y_ki); + ios.printf("Aktuelle Werte fuer Regler Z-Achse: kp = %f kd = %f ki = %f\n\n", + z_kp, z_kd, z_ki); + ios.printf("Menueauswahl:\n"); + ios.printf("\t1 - Regelparameter aendern?\n"); + ios.printf("\t2 - Plattform aktivieren\n"); + ios.printf("\t3 - Auswahl abbrechen (esc).\n"); + ios.printf("\nEingabe >"); + ios.scanf("%i", &choice4); + }while (choice4 < 1 || choice4 > 3); + + if (choice4 == 1) + { + /* + ios.printf("\n Reglerparameter x_kp eingeben [0 - +3] >"); + ios.scanf("%f", &x_kp); + if (x_kp > x_kp_max) x_kp = x_kp_max; // Begrenzung X-Achse kp Pos. + if (x_kp < x_kp_min) x_kp = x_kp_min; // Begrenzung X-Achse kp Neg. + ios.printf("\n Reglerparameter x_kd eingeben [0 - +3] >"); + ios.scanf("%f", &x_kd); + if (x_kd > x_kd_max) x_kd = x_kd_max; // Begrenzung X-Achse kd Pos. + if (x_kd < x_kd_min) x_kd = x_kd_min; // Begrenzung X-Achse kd Neg. + ios.printf("\n Reglerparameter x_ki eingeben [0 - +0.5] >"); + ios.scanf("%f", &x_ki); + if (x_ki > x_ki_max) x_ki = x_ki_max; // Begrenzung X-Achse ki Pos. + if (x_ki < x_ki_min) x_ki = x_ki_min; // Begrenzung X-Achse ki Neg. + ios.printf("\n Reglerparameter y_kp eingeben [0 - +3] >"); + ios.scanf("%f", &y_kp); + if (y_kp > y_kp_max) y_kp = y_kp_max; // Begrenzung Y-Achse kp Pos. + if (y_kp < y_kp_min) y_kp = y_kp_min; // Begrenzung Y-Achse kp Neg. + ios.printf("\n Reglerparameter y_kd eingeben [0 - +3] >"); + ios.scanf("%f", &y_kd); + if (y_kd > y_kd_max) y_kd = y_kd_max; // Begrenzung Y-Achse kd Pos. + if (y_kd < y_kd_min) y_kd = y_kd_min; // Begrenzung Y-Achse kd Neg. + ios.printf("\n Reglerparameter y_ki eingeben [0 - +0.5] >"); + ios.scanf("%f", &y_ki); + if (y_ki > y_ki_max) y_ki = y_ki_max; // Begrenzung Y-Achse ki Pos. + if (y_ki < y_ki_min) y_ki = y_ki_min; // Begrenzung Y-Achse ki Neg. + */ + ios.printf("\n Reglerparameter z_kp eingeben [0 - +3] >"); + ios.scanf("%f", &z_kp); + if (z_kp > z_kp_max) z_kp = z_kp_max; // Begrenzung Z-Achse kp Pos. + if (z_kp < z_kp_min) z_kp = z_kp_min; // Begrenzung Z-Achse kp Neg. + ios.printf("\n Reglerparameter z_kd eingeben [0 - +3] >"); + ios.scanf("%f", &z_kd); + if (z_kd > z_kd_max) z_kd = z_kd_max; // Begrenzung Z-Achse kd Pos. + if (z_kd < z_kd_min) z_kd = z_kd_min; // Begrenzung Z-Achse kd Neg. + ios.printf("\n Reglerparameter z_ki eingeben [0 - +0.5] >"); + ios.scanf("%f", &z_ki); + if (z_ki > z_ki_max) z_ki = z_ki_max; // Begrenzung Z-Achse ki Pos. + if (z_ki < z_ki_min) z_ki = z_ki_min; // Begrenzung Z-Achse ki Neg. + ios.printf("\n\n"); + //ios.printf("Aktuelle Werte fuer Regler X-Achse: kp = %f kd = %f ki = %f\n\n", + // x_kp, x_kd, x_ki); + //ios.printf("Aktuelle Werte fuer Regler Y-Achse: kp = %f kd = %f ki = %f\n\n", + // y_kp, y_kd, y_ki); + ios.printf("Aktuelle Werte fuer Regler Z-Achse: kp = %f kd = %f ki = %f\n\n", + z_kp, z_kd, z_ki); + } + else if (choice4 == 2) + { + ios.printf("\n\nUm abzubrechen bitte Reset-Taste an mbed betaetigen!\n\n"); + float ziel_x_winkel = data.Roll; + float ziel_y_winkel = data.Pitch; + float ziel_z_winkel = data.Yaw; + + print_gyro_angles(); + float x_dyn_leistung_leerlauf = (min_leistung + max_leistung)/2; // Leistung im Leerlauf + float y_dyn_leistung_leerlauf = (min_leistung + max_leistung)/2; // Leistung im Leerlauf + float z_dyn_leistung_leerlauf = (min_leistung + max_leistung)/2; // Leistung im Leerlauf + + wait_ms(2000); + z_kreisel.write(calcStellwert(z_dyn_leistung_leerlauf)); + //y_kreisel.write(calcStellwert(y_dyn_leistung_leerlauf)); + //x_kreisel.write(calcStellwert(x_dyn_leistung_leerlauf)); + + while(1) + { + while (fabs(ziel_z_winkel - data.Yaw) > regelgenauigkeit) + { + LageregelungAchseDyn(z_kp, z_kd, z_ki, ziel_z_winkel - data.Yaw, data.Gyro_Proc_Z, + data.Yaw, z_kreisel, z_dyn_leistung_leerlauf); + } + + /* + while (fabs(ziel_y_winkel - data.Pitch) > regelgenauigkeit) + { + LageregelungAchseDyn(y_kp, y_kd, y_ki, ziel_y_winkel - data.Roll, data.Gyro_Proc_Y, + data.Pitch, y_kreisel, y_dyn_leistung_leerlauf); + } + + while (fabs(ziel_x_winkel - data.Roll) > regelgenauigkeit) + { + LageregelungAchseDyn(x_kp, x_kd, x_ki, ziel_x_winkel - data.Pitch, data.Gyro_Proc_X, + data.Roll, x_kreisel, x_dyn_leistung_leerlauf); + } + */ + } + } + }while(choice4 != 3); + } + else if (choice1 == 4) + { + print_gyro_data(); + } + + }while(choice1 != 5); + + ios.printf("\n\nProgramm beendet.\n"); +} \ No newline at end of file
diff -r 000000000000 -r 1447d2f773db mbed.bld --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbed.bld Wed Jul 09 07:35:50 2014 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/mbed_official/code/mbed/builds/a9913a65894f \ No newline at end of file