[ell-i-developers] Re: FYI: ENCx24J600 driver ; SPI testing

  • From: Asif Sardar <engr.asif.sardar@xxxxxxxxxxxxxx>
  • To: Pekka Nikander <pekka.nikander@xxxxxx>, ell-i-developers@xxxxxxxxxxxxx
  • Date: Thu, 3 Jul 2014 20:09:03 +0300

I was compiling the SPI from library by including the .o files inside the
app.mk e.g. following lines added

*APP_OBJS ?= main.o $(APP).o $(VARIANT).o wiring_digital.o
wiring_digital_pinMode.o ellduino_Serial.o ellduino_spi.o SPIClass.o
spiStruct.o*

*VPATH += $(TOP)cores/arduelli $(TOP)variants/$(VARIANT)
$(TOP)libraries/SPI*

Also, I splitted the wiring_digital.h and wiring_digital_pinmode.h into
there own source (.c) files to avoid multiple declaration, because the
SPIClass.h is also including the wiring_digital.h using the digitalWrite
and pinMode functions. The files are attached to the e-mail.

Still I am getting following error:

*ellduino_spi.o: In function `SPIClass::begin(unsigned char) const':*
*/home/asif/Ell-i-Working-Directory/Ell-i-Software-Development/Runtime/stm32/build/../libraries/SPI/./SPIClass.h:81:
undefined reference to `digitalWrite'*
*ellduino_spi.o: In function `SPIClass::activate_ss(unsigned char)':*
*/home/asif/Ell-i-Working-Directory/Ell-i-Software-Development/Runtime/stm32/build/../libraries/SPI/./SPIClass.h:183:
undefined reference to `digitalWrite'*
*ellduino_spi.o: In function `SPIClass::deactivate_ss(unsigned char)':*
*/home/asif/Ell-i-Working-Directory/Ell-i-Software-Development/Runtime/stm32/build/../libraries/SPI/./SPIClass.h:184:
undefined reference to `digitalWrite'*

Any good ideas?




On Thu, Jul 3, 2014 at 1:52 PM, Asif Sardar <engr.asif.sardar@xxxxxxxxxxxxxx
> wrote:

> Ok. I will update you the status tomorrow evening. If there are issues I
> need to ask, I will inform you by then.
>
>
> On Thu, Jul 3, 2014 at 1:42 PM, Pekka Nikander <pekka.nikander@xxxxxx>
> wrote:
>
>> Asif,
>>
>> Sounds very good.  I would need it by Wednesday morning, if possible.
>>  Sooner would be better, of course, but realistically I won't have real
>> time to test the ENCx24J600 code before that.  Having SPI more-or-less
>> working in the emulator would make things easier to test.
>>
>> Depending on your progress, we could have a telco on that on e.g. Tuesday
>> morning, to see what's been done.  And of course continue with email here.
>>
>> --Pekka
>>
>> On 2014–07–03, at 13:36 , Asif Sardar <engr.asif.sardar@xxxxxxxxxxxxxx>
>> wrote:
>>
>> > Hello,
>> >
>> > Yes, it has been done for emulator. Atleast, I can see the .o object
>> file for SPI under Runtime/build folder. I have to make a C interface for
>> the SPI in library/SPI/ellduino_spi.h & .c files, just like I did
>> modification for the serial communication in attached files. Such
>> modification is required because the ctypes module cannot access the class
>> member functions directly through the shared library.
>> >
>> > I can try testing them with emulator! When does it needed?
>> >
>> > BR,
>> > Asif.
>> >
>> >
>> > On Thu, Jul 3, 2014 at 1:14 PM, Pekka Nikander <pekka.nikander@xxxxxx>
>> wrote:
>> > The emulator has some SPI done, see SPIemu.h, SPI.cpp.  I don't
>> remember what is the status.  It is probably just on the physical layer,
>> most probably the library is not compiled in, but I just don't remember and
>> don't have time to check right now.
>> >
>> > --pekka
>> >
>> > On 2014–07–03, at 12:51 , Asif Sardar <engr.asif.sardar@xxxxxxxxxxxxxx>
>> wrote:
>> >
>> > > Hello,
>> > >
>> > > Yes. The SPI test cases are ready. I have seen in runtime that SPI
>> has interface already e.g. begin(), end(), setdatamode() etc.But, I didn't
>> see it in emulator.
>> > >
>> > > BR,
>> > > Asif.
>> > >
>> > >
>> > > On Thu, Jul 3, 2014 at 12:43 PM, Pekka Nikander <
>> pekka.nikander@xxxxxx> wrote:
>> > > Otso,
>> > >
>> > > FYI: I've started writing the ENCx24J600 driver.  Looks simple and
>> straightforward, just work.  I'll make it separate from the ENC28J60
>> driver, as it will most probably be smaller (smaller flash footprint) than
>> the ENC28J60 driver, if done right.
>> > >
>> > > My current estimate is that I'll have first version ready by Monday
>> or Tuesday.  It may or may not be complete, but in any case should be good
>> enough for testing on Wednesday.  As usual, I will most probably run out of
>> time before we'll get it fully tested, though....
>> > >
>> > > Asif,
>> > >
>> > > What's the situation with SPI library test cases?  Do we have any yet?
>> > >
>> > > --Pekka
>> > >
>> > >
>> > >
>> > >
>> > > --
>> > > With Best Regards,
>> > > Asif Sardar.
>> > > +358 43 8265795
>> >
>> >
>> >
>> >
>> > --
>> > With Best Regards,
>> > Asif Sardar.
>> > +358 43 8265795
>> > <ellduino_Serial.c><ellduino_Serial.h>
>>
>>
>
>
> --
>
>
>
> *With Best Regards,Asif Sardar.+358 43 8265795 <%2B358%2043%208265795>*
>



-- 



*With Best Regards,Asif Sardar.+358 43 8265795*
#include "arduelli_gpio.h"
#include "ellduino_gpio.h" // XXX replace with variant_gpio.h

#ifdef EMULATOR

//extern "C" {
        int digitalRead(pin_t pin) {
        return GPIOPIN[pin].gpio_port->IDR & GPIOPIN[pin].gpio_mask? 1: 0;
    }
//}

// extern "C" {
        void  digitalWrite(pin_t pin, uint32_t val) {
        if (val) {
            GPIOPIN[pin].gpio_port->BSRR = GPIOPIN[pin].gpio_mask;
            uint32_t value = 0;
           value &= ~(GPIOPIN[pin].gpio_mask >> 16);
           value |= (GPIOPIN[pin].gpio_mask & 0xffff);
           GPIOPIN[pin].gpio_port->ODR  = value;
           GPIOPIN[pin].gpio_port->IDR  = value;
        }
        else {
            GPIOPIN[pin].gpio_port->BRR  = GPIOPIN[pin].gpio_mask;
            uint32_t value = 0;
           value &= ~(GPIOPIN[pin].gpio_mask);
           GPIOPIN[pin].gpio_port->ODR  = value;
           GPIOPIN[pin].gpio_port->IDR  = value;
            //parent_.IDR.value_ = parent_.ODR.value_;
        }
    }
//}

#else

static inline
int digitalRead(pin_t pin) {
    return GPIOPIN[pin].gpio_port->IDR & GPIOPIN[pin].gpio_mask? 1: 0;
}
static inline
void  digitalWrite(pin_t pin, uint32_t val) {
    if (val)
        GPIOPIN[pin].gpio_port->BSRR = GPIOPIN[pin].gpio_mask;
    else
        GPIOPIN[pin].gpio_port->BRR  = GPIOPIN[pin].gpio_mask;
}

#endif
/*
 * Copyright (c) 2013-2014 ELL-i co-operative
 *
 * This file is part of ELL-i software.
 *
 * ELL-i software is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * ELL-i software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with ELL-i software.  If not, see <http://www.gnu.org/licenses/>.
 */

/**
 * @author Pekka Nikander <pekka.nikander@xxxxxxxxx>  2013-2014
 */

#ifndef _WIRING_DIGITAL_H_
# define _WIRING_DIGITAL_H_

//#include "arduelli_gpio.h"
//#include "ellduino_gpio.h" // XXX replace with variant_gpio.h

/**************************************
 * Arduino APIs
 */

#include "wiring_digital_pinMode.h"

#ifdef __cplusplus
    extern "C" {
#endif
    int digitalRead(pin_t pin);
    void  digitalWrite(pin_t pin, uint32_t val);
#ifdef __cplusplus
}
#endif

/*

//To avoid multiple definitions in other files, I split it to 
//source file -> wiring_digital.c

#ifdef EMULATOR

extern "C" {
//static inline
    int digitalRead(pin_t pin) {
        return GPIOPIN[pin].gpio_port->IDR & GPIOPIN[pin].gpio_mask? 1: 0;
    }
}

extern "C" {
//static inline
    void  digitalWrite(pin_t pin, uint32_t val) {
        if (val) {
            GPIOPIN[pin].gpio_port->BSRR = GPIOPIN[pin].gpio_mask;
            uint32_t value = 0;
           value &= ~(GPIOPIN[pin].gpio_mask >> 16);
           value |= (GPIOPIN[pin].gpio_mask & 0xffff);
           GPIOPIN[pin].gpio_port->ODR  = value;
           GPIOPIN[pin].gpio_port->IDR  = value;
        }
        else {
            GPIOPIN[pin].gpio_port->BRR  = GPIOPIN[pin].gpio_mask;
            uint32_t value = 0;
           value &= ~(GPIOPIN[pin].gpio_mask);
           GPIOPIN[pin].gpio_port->ODR  = value;
           GPIOPIN[pin].gpio_port->IDR  = value;
            //parent_.IDR.value_ = parent_.ODR.value_;
        }
    }
}

#else

extern "C" {
//static inline
int digitalRead(pin_t pin) {
    return GPIOPIN[pin].gpio_port->IDR & GPIOPIN[pin].gpio_mask? 1: 0;
}
}

extern "C" {
//static inline
void  digitalWrite(pin_t pin, uint32_t val) {
    if (val)
        GPIOPIN[pin].gpio_port->BSRR = GPIOPIN[pin].gpio_mask;
    else
        GPIOPIN[pin].gpio_port->BRR  = GPIOPIN[pin].gpio_mask;
}
}

#endif
*/

#endif//_WIRING_DIGITAL_H_
#include "wiring_digital_pinMode.h"

//extern "C" {
//static inline
void pinMode(pin_t pin, const enum pin_mode mode) {

    const uint32_t pin_shift = (GPIOPIN[pin].gpio_pin * 2);

    switch (mode) {
    case INPUT:
        /* High impedance: push up/down register bits zero */
        GPIOPIN[pin].gpio_port->PUPDR &= ~(GPIO_PUPDR_PUPDR0 << pin_shift);
        break;
    case INPUT_PULLUP: {
        /* Pull-up: push up/down register bits 01 */
        register uint32_t pupdr = GPIOPIN[pin].gpio_port->PUPDR;
        pupdr |=  (GPIO_PUPDR_PUPDR0_0 << pin_shift);
        pupdr &= ~(GPIO_PUPDR_PUPDR0_1 << pin_shift);
        GPIOPIN[pin].gpio_port->PUPDR = pupdr;
        break;
    }
    case INPUT_PULLDOWN: {
        /* Pull-down: push up/down register bits 10 */
        register uint32_t pupdr = GPIOPIN[pin].gpio_port->PUPDR;
        pupdr &= ~(GPIO_PUPDR_PUPDR0_0 << pin_shift);
        pupdr |=  (GPIO_PUPDR_PUPDR0_1 << pin_shift);
        GPIOPIN[pin].gpio_port->PUPDR = pupdr;
        break;
    }
    case OUTPUT:
        break;
    }

    switch (mode) {
    case OUTPUT: {
        /* Output mode:  mode register bits 01 */
        register uint32_t moder = GPIOPIN[pin].gpio_port->MODER;
        moder |=  (GPIO_MODER_MODER0_0 << pin_shift);
        moder &= ~(GPIO_MODER_MODER0_1 << pin_shift);
        GPIOPIN[pin].gpio_port->MODER = moder;
        break;
    }
    case INPUT:
    case INPUT_PULLUP:
    case INPUT_PULLDOWN:
        /* Input mode: mode register bits zero */
        GPIOPIN[pin].gpio_port->MODER &= ~(GPIO_MODER_MODER0 << pin_shift);
    }
}
//}
/*
 * Copyright (c) 2013-2014 ELL-i co-operative
 *
 * This file is part of ELL-i software.
 *
 * ELL-i software is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * ELL-i software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with ELL-i software.  If not, see <http://www.gnu.org/licenses/>.
 */

/**
 * @author Pekka Nikander <pekka.nikander@xxxxxxxxx>  2013-2014
 */

/**
 * Arduino pinMode
 *
 * Configuration records each GPIO pin as input or output, with the desired 
pullups.
 */

#if defined(ARDUELLI_FEATURE_STATIC_PINMODE)

/*
 * Static, data driven version of the Arduino pinMode() API.
 *
 * This version attempts to cut the amount of generated code through
 * assembling couple a static data structures and then calling
 * SystemInitMaskAndValue() with the static data structures as the
 * argument.  The rationale is that if the compiler is smart enough,
 * it is able to compute the static data structure contents at compile
 * time and assemble the data structures at compile time.
 *
 * Unfortunately, GCC 4.7.1 is not quite smart enough.  It manages to
 * use constant propagation to compute all of the initialisation
 * values at compile time, but it still fails to generate the actual
 * structs at compile time.  Instead, it generates explicit code that
 * initialises the data structures at run time.  Hence, with gcc (and
 * therefore by default) we don't use this version.
 *
 * XXX Test with LLVM to see if it manages to do it right.
 */
#  define DEFINE_pinMode(pin, mode)                                     \
    static const                                                        \
    SystemInitRecordMaskAndValue GPIO_PIN_MODE_Records[] = {            \
        {                                                               \
            .init_r_address = (volatile preg32_t *const)(               \
                (volatile char *const)GPIOPIN[pin].gpio_port            \
                + ((char *const)&GPIOA->MODER - (char *const)GPIOA)),   \
            .init_r_mask    = ~(GPIO_MODER_MODER ## pin),               \
            .init_r_value   = GPIO_pin_mode_moder_values[mode],         \
        }, {                                                            \
            .init_r_address = (volatile preg32_t *const)(               \
                (volatile char *const)GPIOPIN[pin].gpio_port            \
                + ((char *const)&GPIOA->PUPDR - (char *const)GPIOA)),   \
            .init_r_mask    = ~(GPIO_PUPDR_PUPDR ## pin),               \
            .init_r_value   = GPIO_pin_mode_pupdr_values[mode],         \
        }                                                               \
    }

#  define INIT_pinMode(pin, mode)                                       \
    StaticInitMaskAndValue(COUNT_OF(GPIO_PIN_MODE_Records),             \
                     GPIO_PIN_MODE_Records)

/**
 * XXX TBD
 */

#  define pinMode(pin, mode) {                                          \
        DEFINE_pinMode(pin, mode);                                      \
        INIT_pinMode(pin, mode);                                        \
    } while (0)

#else

/**
 * Arduino pinMode API.
 * @param pin   Pin whose mode to change.
 * @param mode  The new mode for pin.
 *
 * Dynamic, sequential, inlined version of the Arduiono pinMode() API.
 *
 * With GCC, generates fair but not optimal code.
 */

//To avoid multiple definitions in other files, I split it to 
//source file -> wiring_digital_pinMode.c

#include "arduelli_gpio.h"
#include "ellduino_gpio.h"

#ifdef __cplusplus
    extern "C" {
#endif
    void pinMode(pin_t pin, const enum pin_mode mode);
#ifdef __cplusplus
}
#endif

 /*
extern "C" {
//static inline
void pinMode(pin_t pin, const enum pin_mode mode) {

    const uint32_t pin_shift = (GPIOPIN[pin].gpio_pin * 2);

    switch (mode) {
    case INPUT:
        // High impedance: push up/down register bits zero 
        GPIOPIN[pin].gpio_port->PUPDR &= ~(GPIO_PUPDR_PUPDR0 << pin_shift);
        break;
    case INPUT_PULLUP: {
        // Pull-up: push up/down register bits 01 
        register uint32_t pupdr = GPIOPIN[pin].gpio_port->PUPDR;
        pupdr |=  (GPIO_PUPDR_PUPDR0_0 << pin_shift);
        pupdr &= ~(GPIO_PUPDR_PUPDR0_1 << pin_shift);
        GPIOPIN[pin].gpio_port->PUPDR = pupdr;
        break;
    }
    case INPUT_PULLDOWN: {
        // Pull-down: push up/down register bits 10 
        register uint32_t pupdr = GPIOPIN[pin].gpio_port->PUPDR;
        pupdr &= ~(GPIO_PUPDR_PUPDR0_0 << pin_shift);
        pupdr |=  (GPIO_PUPDR_PUPDR0_1 << pin_shift);
        GPIOPIN[pin].gpio_port->PUPDR = pupdr;
        break;
    }
    case OUTPUT:
        break;
    }

    switch (mode) {
    case OUTPUT: {
        // Output mode:  mode register bits 01 
        register uint32_t moder = GPIOPIN[pin].gpio_port->MODER;
        moder |=  (GPIO_MODER_MODER0_0 << pin_shift);
        moder &= ~(GPIO_MODER_MODER0_1 << pin_shift);
        GPIOPIN[pin].gpio_port->MODER = moder;
        break;
    }
    case INPUT:
    case INPUT_PULLUP:
    case INPUT_PULLDOWN:
        // Input mode: mode register bits zero 
        GPIOPIN[pin].gpio_port->MODER &= ~(GPIO_MODER_MODER0 << pin_shift);
    }
}
}
*/

#endif
#
# Copyright (c) 2013-2014 ELL-i co-operative
#
# Compile and link an application
#

TOP ?=../
MAKEDIR ?= $(TOP)make/

#
# Define the variant to build for
#
VARIANT ?= ellduino

#
# Set up the compilation environment, identical to the Arduino IDE,
# and include system lib building; we depend on system libraries
#
include $(MAKEDIR)$(PLATFORM).mk
include $(MAKEDIR)system_libs_inc.mk
include $(MAKEDIR)libs_inc.mk

#
# Define the app name
#

APP ?= sketch

#
# Define app library objects.  Add new objects here.
#

#ellduino_Serial.o shall be made automatically like ellduino_timer.o and other 
.o files
APP_OBJS ?= main.o $(APP).o $(VARIANT).o wiring_digital.o 
wiring_digital_pinMode.o \
        ellduino_Serial.o ellduino_spi.o SPIClass.o spiStruct.o

#
# Rules
#

VPATH += $(TOP)cores/arduelli $(TOP)variants/$(VARIANT) $(TOP)libraries/SPI

all:  $(APP) $(APP).hex libemulator.so

clean::
        rm -f $(APP)
        rm -f $(APP).hex
        rm -f $(APP).lst
        rm -f $(APP_OBJS)
        rm -f $(PRE_OBJS)
        rm -f $(POST_OBJS)
        rm -f make.map
        rm -f libemulator.so
        rm -f *.o

$(APP): $(APP_OBJS) $(SYSTEM_LIBS) $(PRE_OBJS) $(POST_OBJS)
        $(LD) $(LDFLAGS) -o $@ $(PRE_OBJS) $(APP_OBJS) $(LIBS) $(POST_OBJS)

#
# Define rules for producing .hex files
#

.PHONY: .hex

%.hex:  %
        $(ELF2HEX) $(EHFLAGS) $< $@

libemulator.so: $(SYSTEM_LIBS) $(PRE_OBJS) $(POST_OBJS)
        $(LD) $(LDFLAGS) $(SHAREDFLAGS) -o $@ $(PRE_OBJS) $(APP_OBJS) $(LIBS) 
$(POST_OBJS)
/*
 * Copyright (c) 2014 ELL-i co-operative
 *
 * This file is part of ELL-i software.
 *
 * ELL-i software is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * ELL-i software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with ELL-i software.  If not, see <http://www.gnu.org/licenses/>.
 */

/**
 * @author Pekka Nikander <pekka.nikander@xxxxxxxxx>  2014
 *
 * @brief The Arduino library SPI class
 */

#ifndef _SPI_CLASS_H_
#define _SPI_CLASS_H_

#include <stm32f0xx.h>
#include <spiStruct.h>
#include <ellduino_gpio.h>   // XXX To be placed into the variant.h!
#include <arduelli_thread.h> // XXX TBD -- is this the right file name?
#include <wiring_digital.h>
#include <TinyMap.h>

#ifndef BOARD_SPI_DEFAULT_SS
#define BOARD_SPI_DEFAULT_SS 10 /* XXX */
#endif

enum SPITransferMode {
    SPI_CONTINUE,
    SPI_LAST
};

enum SPIBitOrder {
    MSBFIRST = !SPI_CR1_LSBFIRST,
    LSBFIRST =  SPI_CR1_LSBFIRST,
};

enum SPIClockDivider {
    SPI_CLOCK_DIV2   = !SPI_CR1_BR_2 | !SPI_CR1_BR_1 | !SPI_CR1_BR_0,
    SPI_CLOCK_DIV4   = !SPI_CR1_BR_2 | !SPI_CR1_BR_1 |  SPI_CR1_BR_0,
    SPI_CLOCK_DIV8   = !SPI_CR1_BR_2 |  SPI_CR1_BR_1 | !SPI_CR1_BR_0,
    SPI_CLOCK_DIV16  = !SPI_CR1_BR_2 |  SPI_CR1_BR_1 |  SPI_CR1_BR_0,
    SPI_CLOCK_DIV32  =  SPI_CR1_BR_2 | !SPI_CR1_BR_1 | !SPI_CR1_BR_0,
    SPI_CLOCK_DIV64  =  SPI_CR1_BR_2 | !SPI_CR1_BR_1 |  SPI_CR1_BR_0,
    SPI_CLOCK_DIV128 =  SPI_CR1_BR_2 |  SPI_CR1_BR_1 | !SPI_CR1_BR_0,
    SPI_CLOCK_DIV256 =  SPI_CR1_BR_2 |  SPI_CR1_BR_1 |  SPI_CR1_BR_0,
};

enum SPIDataMode {
    SPI_MODE0 = !SPI_CR1_CPHA | !SPI_CR1_CPOL,
    SPI_MODE1 =  SPI_CR1_CPHA | !SPI_CR1_CPOL,
    SPI_MODE2 = !SPI_CR1_CPHA |  SPI_CR1_CPOL,
    SPI_MODE3 =  SPI_CR1_CPHA |  SPI_CR1_CPOL,
};


/**
 * Type for mapping Arduino PIN numbers to SPI CR1 register values.
 */
typedef TinyMap<uint8_t,uint32_t,7> Pin2Int7;

//XXX TODO: Figure out a better implementation for setClock

class SPIClass {
public:
    const struct SPI &spi_;
    constexpr SPIClass(const SPI &spi, Pin2Int7 &ssPinCR1) : spi_(spi), 
ssPinCR1_(ssPinCR1) {};
    void begin(const uint8_t ss_pin = BOARD_SPI_DEFAULT_SS) const {
        digitalWrite(ss_pin, 1); /* Avoid glitch */
        pinMode(ss_pin, OUTPUT);
        spi_master_begin(&spi_);
        ssPinCR1_[ss_pin] = 0
                            | ! SPI_CR1_CPHA       /* Data at first edge */
                            | ! SPI_CR1_CPOL       /* Clock low when idle */
                            |   SPI_CR1_MSTR       /* Master mode */
                            |   SPI_CR1_BR_1       /* Clock divider 8 */
                            |   SPI_CR1_SPE        /* SPI enabled */
                            | ! SPI_CR1_LSBFIRST   /* MSB first */

                            |   SPI_CR1_SSI        /* Internal NSS high, needed 
for master mode */
                            |   SPI_CR1_SSM        /* Software Slave management 
enabled */
                            | ! SPI_CR1_RXONLY     /* 0: Full duplex */
                            | ! SPI_CR1_CRCL       /* 0: N/A (8-bit CRC length) 
*/
                            | ! SPI_CR1_CRCNEXT    /* 0: Transmit TX buffer, 
not CERC */
                            | ! SPI_CR1_CRCEN      /* 0: CRC disabled */
                            |   SPI_CR1_BIDIOE     /* 1: Output enabled */
                            | ! SPI_CR1_BIDIMODE   /* 0: 2-Line 
(uni)directional data */
                            ;

    };

    void end(const uint8_t ss_pin) const {
        pinMode(ss_pin, INPUT /* XXX DEFAULT */);
    };

    void end(void) const {
        /* XXX Semantic inconsistency with begin(void) */
        spi_master_end(&spi_);
    }

    void setBitOrder(const SPIBitOrder bitOrder) const {
        setBitOrder(BOARD_SPI_DEFAULT_SS, bitOrder);
    }
    void setBitOrder(const uint8_t ss_pin, const SPIBitOrder bitOrder) const {
        ssPinCR1_[ss_pin] &= ~SPI_CR1_LSBFIRST;
        ssPinCR1_[ss_pin] |=  bitOrder;
    }

    uint32_t setClockDivider(const SPIClockDivider clockDivider) const {
        return setClockDivider(BOARD_SPI_DEFAULT_SS, clockDivider);
    }
    uint32_t setClockDivider(const uint8_t ss_pin, const SPIClockDivider 
clockDivider) const {
        uint32_t oldValue = ssPinCR1_[ss_pin] & SPI_CR1_BR;
        ssPinCR1_[ss_pin] &= ~SPI_CR1_BR;
        ssPinCR1_[ss_pin] |= clockDivider;
        return oldValue;
    }

    uint32_t setClock(const uint32_t hertz) const {
        return setClock(BOARD_SPI_DEFAULT_SS, hertz);
    }
    uint32_t setClock(const uint8_t ss_pin, const uint32_t hertz) const {
        uint32_t outputHertz = SystemCoreClock>>1;
        uint8_t wantedDivider = 0;
        SPIClockDivider wantedDividerEnum;
        
        if (hertz<outputHertz)
        {
            for (wantedDivider=1; wantedDivider < 7; wantedDivider++){
                outputHertz>>=1;
                if (hertz >= outputHertz) break;
            }
        }
        
        //XXX There should be a better way than typecasting.
        wantedDividerEnum =  static_cast<SPIClockDivider>(wantedDivider<<3);
        setClockDivider(ss_pin, wantedDividerEnum);
        return outputHertz;
    }

    void setDataMode(SPIDataMode dataMode) const {
        setDataMode(BOARD_SPI_DEFAULT_SS, dataMode);
    }
    void setDataMode(uint8_t ss_pin, SPIDataMode dataMode) const {
        ssPinCR1_[ss_pin] &= ~(SPI_CR1_CPHA | SPI_CR1_CPOL);
        ssPinCR1_[ss_pin] |=  dataMode;
    }

    uint8_t transfer(uint8_t data, SPITransferMode mode = SPI_LAST) const {
        return transfer(BOARD_SPI_DEFAULT_SS, data, mode);
    }

    uint8_t transfer(uint8_t ss_pin, uint8_t data, SPITransferMode mode = 
SPI_LAST) const {
        return transfer(ss_pin, &data, 1, mode);
    }

    uint8_t transfer(uint8_t ss_pin, uint8_t data[], uint8_t len,
                     SPITransferMode mode = SPI_LAST) const {
        activate_ss(ss_pin);

        const uint32_t cr1 = ssPinCR1_[ss_pin];

        len = spi_transfer(&spi_, cr1, data, len);

        if (mode == SPI_LAST)
            deactivate_ss(ss_pin);
        return len;
    };
private:
    Pin2Int7 &ssPinCR1_;
    static inline void activate_ss(uint8_t ss_pin) { digitalWrite(ss_pin, 0); };
    static inline void deactivate_ss(uint8_t ss_pin) { digitalWrite(ss_pin, 1); 
};
};

#endif//_SPI_CLASS_H_
/*
 * Copyright (c) 2014 ELL-i co-operative.
 *
 * ELL-i software is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * ELL-i software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with ELL-i software.  If not, see
 * <http://www.gnu.org/licenses/>.
 */

/*
 * Authors:  Pekka Nikander <pekka.nikander@xxxxxxxxx>  2014
 */

#ifndef _ELLDUINO_SPI_H_
# define _ELLDUINO_SPI_H_

# include <SPIClass.h>
# include <system_init.h>

/**
 * Declarations for externally visible SPI init records.
 *
 * STM32F0 has SPI ports 1 and 2.
 */
SPI_INIT_DEFAULT(1);
SPI_INIT_DEFAULT(2);

#define BOARD_SPI_DEFAULT_SS 10 /* XXX: Should be D10 but that is not defined 
yet */

extern Pin2Int7 spimap1, spimap2;

static const struct SPI __SPI1struct = DEFINE_SPI_STRUCT(1, A, 15, 0, B,  4, 0, 
B,  5, 0, B,  3, 0);
static const struct SPI __SPI2struct = DEFINE_SPI_STRUCT(2, B, 12, 0, B, 14, 0, 
B, 15, 0, B, 13, 0);

static const class SPIClass SPI  (__SPI1struct, spimap1);
static const class SPIClass SPI_2(__SPI2struct, spimap2);

///****************************************************************************************///
///Adding interface for the robotframework to access class member functions.
///****************************************************************************************///
#ifdef EMULATOR
        extern "C" {
                void begin(const uint8_t ss_pin);
                void end(const uint8_t ss_pin);
                void setBitOrder(const uint8_t ss_pin, const SPIBitOrder 
bitOrder);
                uint32_t setClockDivider(const uint8_t ss_pin, const 
SPIClockDivider clockDivider);
                void setDataMode(uint8_t ss_pin, SPIDataMode dataMode);
                uint8_t transfer(uint8_t ss_pin, uint8_t data);

        }
#endif

#endif//_ELLDUINO_SPI_H_

Other related posts: