MAX3100, an external serial device to add additional serial ports via SPI

Dependents:   FLIGHT_CONTROL_AND_COMMUNICATIONS_SYSTEM

MAX3100.h

Committer:
AjK
Date:
2012-08-03
Revision:
2:2a49171453d5
Parent:
1:46c8c60e744a

File content as of revision 2:2a49171453d5:

/*
    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.
*/


#ifndef AJK_MAX31000_H
#define AJK_MAX31000_H

#ifndef MBED_H
#include "mbed.h"
#endif

#ifndef MAX3100_TX_BUFFER_SIZE
#define MAX3100_TX_BUFFER_SIZE  32
#endif

#ifndef MAX3100_RX_BUFFER_SIZE
#define MAX3100_RX_BUFFER_SIZE  32
#endif

#ifndef MAX3100_SPI_FREQ
#define MAX3100_SPI_FREQ    5000000
#endif

#define MAX3100_CONF_WR     (3U << 14)
#define MAX3100_CONF_RD     (1U << 14)
#define MAX3100_CONF_T      (1U << 14)
#define MAX3100_CONF_R      (1U << 15)
#define MAX3100_FEN(x)      (x << 13)
#define MAX3100_SHDNi(x)    (x << 12)
#define MAX3100_TM(x)       (x << 11)
#define MAX3100_RM(x)       (x << 10)
#define MAX3100_PM(x)       (x <<  9)
#define MAX3100_RAM(x)      (x <<  8)
#define MAX3100_IR(x)       (x <<  7)
#define MAX3100_ST(x)       (x <<  6)
#define MAX3100_PE(x)       (x <<  5)
#define MAX3100_L(x)        (x <<  4)
#define MAX3100_BAUD(x)     (x <<  0)        

#define MAX3100_DATA_WR     (2U << 14)
#define MAX3100_DATA_RD     (0)
#define MAX3100_TE(x)       (x << 10)
#define MAX3100_RAFE(x)     (x << 10)
#define MAX3100_RTS(x)      (x <<  9)
#define MAX3100_CTS(x)      (x <<  9)
#define MAX3100_PT(x)       (x <<  8)
#define MAX3100_PR(x)       (x <<  8)

namespace AjK {

class MAX3100Dummy;

/** MAX3100 An external serial IO device.
 *
 * The MAX3100 librray is designed to allow the easy attachment of additional
 * serial ports to the Mbed. We all know that the Mbed already has 3 potential
 * serial ports. But maybe you need more ports or maybe you need to use the Mbed
 * pins for an alternative function. The MAX3100 may well be able to help in 
 * situations like these. 
 *
 * Each MAX3100 device you create in is TX/RX buffered with 32 characters in a circular
 * buffer system.
 *
 * The MAX3100 uses at least one Mbed SPI port and additional DigitalOut and InterruptIn
 * pins to work. However, you can attach multiple MAX3100 devices to a single SPI "bus".
 *
 * For more information on attaching multiple devices see all the examples listed below.
 *
 * @see example1.h
 * @see example2.h
 * @see example3.h
 * @see http://pdfserv.maxim-ic.com/en/ds/MAX3100.pdf
 */
class MAX3100 : public Stream {

protected:
    
    SPI         *_spi;
    DigitalOut  *_cs;
    InterruptIn *_irq;
    
    uint16_t tx_buffer[MAX3100_TX_BUFFER_SIZE];
    int  tx_buffer_in;
    int  tx_buffer_out;
    bool tx_buffer_full;
    
    uint16_t rx_buffer[MAX3100_RX_BUFFER_SIZE];
    int  rx_buffer_in;
    int  rx_buffer_out;
    bool rx_buffer_full;
    
    uint16_t    config;
    int         _device;
    int         _parity;
    
    uint32_t _irqMask0, _irqMask2;
    
    void irqDisable(void);
    void irqEnable(void);
        
    virtual int _putc(int c) { return putc(c); }
    virtual int _getc()      { return getc(); }

    /** init
     *
     * Initialise the device.
     * @param PinName SPI mosi
     * @param PinName SPI miso
     * @param PinName SPI sclk
     * @param PinName DigitalOut cs
     * @param PinName InterruptIn irq
     * @param SPI * A pointer to a shared SPI bus
     */
    void init(PinName mosi, PinName miso, PinName sclk, PinName cs, PinName irq, SPI *spi = (SPI *)NULL);    
    
    uint16_t spiwrite(uint16_t val);        
    uint16_t config_write(uint16_t val);
    uint16_t config_read(void);

    // C style callback function pointer for external CS control.    
    void (*_cs_function)(int, int); 
    
    // C++ style callback method pointer for external CS control
    MAX3100Dummy  *_cs_obj;
    void (MAX3100Dummy::*_cs_method)(int, int);

    // C style callback function pointer for user isr callback.    
    void (*_isr_user_function)(int); 

    // C++ style callback method pointer for external CS control
    MAX3100Dummy  *_isr_user_obj;
    void (MAX3100Dummy::*_isr_user_method)(int);
    
    // Internal CS control.
    void cs_value(int);
    
    // calculate byte parity.
    int parityCal(uint8_t c);

    // http://mbed.org/forum/bugs-suggestions/topic/1498
    void topic_1498(PinName p); 

public:
    
    static const int ISR    = 0;
    
    static const int ISR_RX = 1;
    
    static const int ISR_TX = 2;
    
    /** Constructor
     */
    MAX3100() { error( "No pins supplied to constructor" ); }
    
    /** Constructor
     */
    MAX3100(PinName mosi, PinName miso, PinName sclk, PinName cs, PinName irq, int device = 0) {
        _device = device;
        init( mosi, miso, sclk, cs, irq);
    }
    
    /** Constructor
     */
    MAX3100(SPI *spi, PinName cs, PinName irq, int device = 0) {
        _device = device;
        init( NC, NC, NC, cs, irq, spi);
    }
    
    /** Destructor
     */
    virtual ~MAX3100() { 
        if ( _spi )     delete( _spi );
        if ( _irq )     delete( _irq );
        if ( _cs  )     delete( _cs );
    }

    enum Parity {
        None = 0
        , Odd
        , Even
        , Forced1   
        , Forced0
    };    
    
    /** setParity
     *
     * Set the parity of the system. Default is None.
     *
     * @param Parity None, Odd, Even
     */
    void setParity(int p) { _parity = p; }
    
    /** setStopBits
     *
     * Set the number of stop bits. Default is One.
     *
     * @param int 1 or 2
     */
    void setStopBits(int i);
    
    /** System interrupt service routine.
     */
    void isr(void);
    
    /** baud
     * Set the system baud. Default is "10" (9600). Note,
     * this is not like Mbed's Serial where you pass the
     * baud rate you want. The MAX3100 has 16 possible 
     * preset prescalers you can choose from. See the datasheet
     * for more info. 
     *
     * @see http://pdfserv.maxim-ic.com/en/ds/MAX3100.pdf
     * @param int A number from 0 to 15 indicating which prescaler to use.
     */
    void baud(int baudrate);
    
    /** enableRxIrq
     */
    void enableRxIrq(void);
    
    /** disableRxIrq
     */
    void disableRxIrq(void);
    
    /** enableTxIrq
     */
    void enableTxIrq(void);
    
    /** disableTxIrq
     */
    void disableTxIrq(void);
    
    /** putc
     * @param int c The byte to write.
     */
    int  putc(int c);
    
    /** puts
     * @param char * The string to print.
     */
    void puts(char *s);
    
    /** getc
     * @return int c The byte read or -1 if no bytes to read.
     */
    int  getc(void); 
    
    /** gets
     * Get a string. Note, this method blocks until size bytes are read.
     * @param char *s where to place the incoming bytes.
     * @param int size How many bytes to read.
     * @return char * The value of *s passed in.
     */
    char *gets(char *s, int size);   
    
    /** peek
     * like getc() but does NOT remove the byte from the buffer.
     * @see getc*(
     */
    int  peek(void);
    
    /** readable
     * Are any byte(s) available in the RX buffer?
     * @return 0 if none, 1 otherwise.
     */
    int  readable(void) { return (rx_buffer_in != rx_buffer_out || rx_buffer_full) ? 1 : 0; }
    
    /** writable
     * Can we write a byte to teh serial stream?
     * @return non-zero if we can, zero otherwise.
     */
    int  writable(void) { return tx_buffer_full ? 0 : 1; }
    
    /** setDevice
     * Give this device an "address".
     * @param int i An address to use in callbacks.
     */
    void setDevice(int i) { _device = i; }
    
    /** flushTxBuffer
     *
     * Flush the TX buffer.
     */
    void flushTxBuffer(void) { tx_buffer_in = tx_buffer_out = 0; tx_buffer_full = false; }
    
    /** flushRxBuffer
     *
     * Flush the RX buffer.
     */
    void flushRxBuffer(void) { rx_buffer_in = rx_buffer_out = 0; rx_buffer_full = false; }
    
    /** irqMask
     * Setup the mask for enable/disable interrupts.
     * @see example3.h
     * @param PinName p The InterruptIn pin.
     */
    void irqMask(PinName p);

    /** attach_cs
     * Attach a C style callback function pointer. Used if an external function
     * is controlling the chip CS line.
     * @param function A C function pointer
     */
    void attach_cs(void (*function)(int, int) = 0) { _cs_function = function; }
    
    /** attach_cs
     * Attach a C++ object/method pointer. Used if an external function
     * @param object An object that conatins the callback method.
     * @param method The method within the object to call.
     */
    template<class T> 
    void attach_cs(T* item, void (T::*method)(int, int)) { 
        _cs_obj = (MAX3100Dummy *)item; _cs_method = (void (MAX3100Dummy::*)(int, int))method; 
    }
    
    /** attach_isr_user
     * is controlling the chip CS line.
     * @param function A C function pointer
     */
    void attach_isr_user(void (*function)(int) = 0) { _isr_user_function = function; }
    
    /** attach_isr_user
     * @param object An object that conatins the callback method.
     * @param method The method within the object to call.
     */
    template<class T> 
    void attach_isr_user(T* item, void (T::*method)(int)) { 
        _isr_user_obj = (MAX3100Dummy *)item; _isr_user_method = (void (MAX3100Dummy::*)(int))method; 
    }
    
};

}; // namespace AjK ends.

using namespace AjK;

#endif