Bluetooth enabled control of a BLDC via the Allegro MicroSystems A4960.

Dependencies:   BLE_API mbed nRF51822

Fork of BLE_ModularRobot by Annie Mao

Files at this revision

API Documentation at this revision

Comitter:
anniemao
Date:
Tue May 16 19:31:49 2017 +0000
Parent:
10:af76616e4d75
Commit message:
Annie Mao 2017

Changed in this revision

a4960.cpp Show annotated file Show diff for this revision Revisions of this file
a4960.h Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
spi_master.cpp Show annotated file Show diff for this revision Revisions of this file
spi_master.h Show annotated file Show diff for this revision Revisions of this file
diff -r af76616e4d75 -r 4251b62991ac a4960.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/a4960.cpp	Tue May 16 19:31:49 2017 +0000
@@ -0,0 +1,82 @@
+#include "a4960.h"
+
+a4960::a4960() : SPI(NRF_SPI1), _cs_pin(P0_10), _blink_pin(P0_4), _PWM_pin(P0_15)
+{
+    PWM_freq = 20000.0;
+    PWM_duty = 1;
+    motor_started = false;
+
+    _config[0] = (0x0 << 10) | (0x8 << 6) | (0x14); // 50 us comm blank time, 2.4 us blank time, 200 ns deadtime
+    _config[1] = (0x7 << 6) | (0x0); // Vri = 100% Vref, Vdsth = 800mV
+    _config[2] = (0x10); // 35.6 us current control time
+    _config[3] = (0x0 << 8) | (0x5 << 4) | (0x4); // current limited, 50% current for hold, 18ms hold time
+    _config[4] =  (0x15 << 4) | (0x4); // 0.8ms min comm time, 24 ms start comm time
+    _config[5] = (0x0 << 8) | (0x8 << 4) | (0x0); // 16.875deg phase adv, 100% ramp current, 0.4ms ramp rate
+    _config[6] = (0x0); // fault detection all on
+    _config[7] = (0x0 << 10) | (0x4 << 7) | (0x0 << 6) | (0x0 << 4) | (0x1 << 3) | (0x0 << 2) | (0x0 << 1) | (0x0);
+    // auto BEMF hyst, 3.2us zx det window, no stop on fail, DIAG pin = fault, restart on loss of sync, brake off, forward, coast
+    
+    SPI_init();
+}
+
+void a4960::SPI_init()
+{
+    // initialize pins
+    _cs_pin = 1;
+    _blink_pin = 1;
+    _PWM_pin.period(1/PWM_freq);
+    _PWM_pin.write(PWM_duty);
+    // initialize SPI connection
+    SPI.begin(P0_8, P0_9, P0_11);//SCK, MOSI, MOSI
+    // set registers to default config
+    for (int i = 0; i < 8; i++) {
+        write_to_a4960(i, _config[i]);
+    }
+    // turn off pin to indicate initialization complete
+    _blink_pin = 0;
+}
+void a4960::write_to_a4960(uint8_t addr, uint16_t msg)
+{
+    // split 16-bit message to a4960 into two 8-bit messages
+    uint8_t ms_half;
+    uint8_t ls_half;
+
+    // ---- 1st message (bits 15 - 8)
+    // 3 bit address
+    ms_half = addr << 5;
+    // 12 bit message
+    // shift message to get rid of 8 LSB on the end and OR
+    // the write bit and the
+    // 4 remaining bits into the first-half msg
+    ms_half = ms_half | 1 << 4 | (uint8_t)(msg>>8);
+    // ---- 2nd message (bits 7 - 0)
+    ls_half = (uint8_t)(msg);
+
+    // pull to active low
+    _cs_pin = 0;
+    wait_us(200);
+
+    // transfer the two messages halves, MSB first
+    SPI.transfer(ms_half);
+    SPI.transfer(ls_half);
+
+    // wait and pull CS line back to inactive high
+    wait_us(200);
+    _cs_pin = 1;
+}
+
+void a4960::write_run(void)
+{
+    write_to_a4960(7, _config[7] | 1);
+}
+
+void a4960::write_brake(void)
+{
+    write_to_a4960(7, _config[7]);
+}
+
+
+
+
+
+
diff -r af76616e4d75 -r 4251b62991ac a4960.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/a4960.h	Tue May 16 19:31:49 2017 +0000
@@ -0,0 +1,59 @@
+#ifndef _A4960_H_
+#define _A4960_H_
+
+#include "mbed.h"
+#include "spi_master.h"
+
+class a4960
+{
+public:
+    a4960();
+    void SPI_init();
+    void write_to_a4960(uint8_t addr, uint16_t msg);
+    void write_run();
+    void write_brake();
+    bool motor_started;
+    float PWM_freq; // Hz
+    float PWM_duty; // 0 to 1
+private:
+// the default configurations of the 8 a4960 registers
+// 0. Config0: basic timing settings
+//      CB(2 bits) comm. blank time
+//      BT (4 bits) blank time in 400ns increments
+//      DT (6 bits) dead time in 50ns increments
+// 1. Config1: basic voltage settings
+//      VR (4 bits) current limit reference voltage as ratio of Vref
+//      VT (6 bits) drain-source thresh. voltage in 25 mV increments
+// 2. Config2: PWM settings
+//      PT (5 bits) off-time for PWM current control, limits motor current
+// 3. Config3: start-up hold settings
+//      IDS (1 bit) select current control or duty cycle control for init. holding torque
+//      HQ (4 bits) holding torque for initial start position
+//                  hold current or duty cycle in increments of 6.25%
+//      HT (4 bits) hold time of init. start position, increments of 8ms from 2ms
+// 4. Config4: start-up timing settings
+//      EC (4 bits) end comm. time in incr. of 200us
+//      SC (4 bits) start comm. time in incr. of 8ms
+// 5. Config5: start-up ramp settings
+//      PA (4 bits) phase advance in incr. of 1.875 deg
+//      RQ (4 bits) torque during ramp up (duty cycle or current control dep. on IDS) in 6.25% incr.
+//      RR (4 bits) accel. rate during forced comm. ramp up
+// 6. Mask: fault masking bit for each fault bit in Diagnostic register
+//      each bit: 1 means diagnostic is diabled
+// 7. Run: bits to set running conditions
+//      BH (2 bits) select BEMF hysteresis
+//      BW (3 bits) BEMF window
+//      ESF (1 bit) enable stop on fault
+//      DG (2 bits) select output routed to DIAG terminal, default general fault output flag (low if fault detected)
+//      RSC (1 bit) 1 to enable restart after loss of sync if RUN 1, BRK 0, else coast to stop
+//      BRK (1 bit) brake control
+//      DIR (1 bit) direction control
+//      RUN (1 bit) run control
+    uint16_t _config[8];
+    SPIClass SPI;
+    DigitalOut _cs_pin;
+    DigitalOut _blink_pin;
+    PwmOut _PWM_pin;
+};
+
+#endif
\ No newline at end of file
diff -r af76616e4d75 -r 4251b62991ac main.cpp
--- a/main.cpp	Tue Jan 12 10:34:34 2016 +0000
+++ b/main.cpp	Tue May 16 19:31:49 2017 +0000
@@ -17,9 +17,11 @@
 #include "mbed.h"
 #include "ble/BLE.h"
 #include "LEDService.h"
+#include "a4960.h"
 
-DigitalOut alivenessLED(LED1, 0);
-DigitalOut actuatedLED(LED2, 0);
+DigitalOut alivenessLED(P0_6, 0);
+DigitalOut actuatedLED(P0_7, 0);
+a4960 motor;
 
 const static char     DEVICE_NAME[] = "LED";
 static const uint16_t uuid16_list[] = {LEDService::LED_SERVICE_UUID};
@@ -47,6 +49,14 @@
 void onDataWrittenCallback(const GattWriteCallbackParams *params) {
     if ((params->handle == ledServicePtr->getValueHandle()) && (params->len == 1)) {
         actuatedLED = *(params->data);
+        if (*(params->data))
+        {
+            motor.write_run();
+        }
+        else
+        {
+            motor.write_brake();
+        }
     }
 }
 
diff -r af76616e4d75 -r 4251b62991ac spi_master.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/spi_master.cpp	Tue May 16 19:31:49 2017 +0000
@@ -0,0 +1,236 @@
+/*
+
+Copyright (c) 2012-2014 RedBearLab
+
+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 "spi_master.h"
+
+/**********************************************************************
+name :
+function : 
+**********************************************************************/
+SPIClass::SPIClass(NRF_SPI_Type *_spi) : spi(_spi)
+{
+    //do nothing
+}
+
+/**********************************************************************
+name :
+function : 
+**********************************************************************/
+void SPIClass::setCPOL( bool active_low)
+{
+    if(active_low)
+    {
+        spi->CONFIG |= (SPI_CONFIG_CPOL_ActiveLow << SPI_CONFIG_CPOL_Pos);
+    }
+    else
+    {
+        spi->CONFIG |= (SPI_CONFIG_CPOL_ActiveHigh << SPI_CONFIG_CPOL_Pos);
+    }
+}
+
+/**********************************************************************
+name :
+function : 
+**********************************************************************/
+void SPIClass::setCPHA( bool trailing)
+{
+    if(trailing)
+    {
+        spi->CONFIG |= (SPI_CONFIG_CPHA_Trailing << SPI_CONFIG_CPHA_Pos);
+    }
+    else
+    {
+        spi->CONFIG |= (SPI_CONFIG_CPHA_Leading << SPI_CONFIG_CPHA_Pos);
+    }
+
+}
+
+/**********************************************************************
+name :
+function : MSBFIRST, LSBFIRST
+**********************************************************************/
+void SPIClass::setBitORDER( BitOrder  bit)
+{
+    if(bit == MSBFIRST)
+    {
+        spi->CONFIG |= (SPI_CONFIG_ORDER_MsbFirst << SPI_CONFIG_ORDER_Pos);
+    }
+    else
+    {
+        spi->CONFIG |= (SPI_CONFIG_ORDER_LsbFirst << SPI_CONFIG_ORDER_Pos);
+    }
+}
+
+/**********************************************************************
+name :
+function : 
+**********************************************************************/
+void SPIClass::setFrequency(uint8_t speed)
+{
+    if (speed == 0)
+    {
+        spi->FREQUENCY = SPI_FREQUENCY_125K;
+    }
+    else if (speed == 1)
+    {
+        spi->FREQUENCY = SPI_FREQUENCY_250K;
+    }
+    else if (speed == 2)
+    {
+        spi->FREQUENCY = SPI_FREQUENCY_500K;
+    }
+    else if (speed == 3)
+    {
+        spi->FREQUENCY = SPI_FREQUENCY_1M;
+    }
+    else if (speed == 4)
+    {
+        spi->FREQUENCY = SPI_FREQUENCY_2M;
+    }
+    else if (speed == 5)
+    {
+        spi->FREQUENCY = SPI_FREQUENCY_4M;
+    }
+    else if (speed == 6)
+    {
+        spi->FREQUENCY = SPI_FREQUENCY_8M;
+    }
+    else
+    {
+        spi->FREQUENCY = SPI_FREQUENCY_4M;
+    }   
+}
+
+/**********************************************************************
+name :
+function : 
+**********************************************************************/
+void SPIClass::setSPIMode( uint8_t mode )
+{
+    if (SPI_MODE0 == mode)
+    {
+        setCPOL(0);
+        setCPHA(0);     
+    }
+    else if (mode == SPI_MODE1)
+    {
+        setCPOL(0);
+        setCPHA(1);
+    }
+    else if (mode == SPI_MODE2)
+    {
+        setCPOL(1);
+        setCPHA(0);
+    }
+    else if (mode == SPI_MODE3)
+    {
+        setCPOL(1);
+        setCPHA(1);
+    }
+    else
+    {
+        setCPOL(0);
+        setCPHA(0);         
+    }
+}
+
+/**********************************************************************
+name :
+function : 
+**********************************************************************/
+void SPIClass::begin(uint32_t sck, uint32_t mosi, uint32_t miso)
+{
+
+        SCK_Pin = sck;
+        MOSI_Pin = mosi;
+        MISO_Pin = miso;
+        
+        NRF_GPIO->PIN_CNF[SCK_Pin] = (GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos)
+                                        | (GPIO_PIN_CNF_DRIVE_S0S1 << GPIO_PIN_CNF_DRIVE_Pos)
+                                        | (GPIO_PIN_CNF_PULL_Disabled << GPIO_PIN_CNF_PULL_Pos)
+                                        | (GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos)
+                                        | (GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos);    
+                                        
+        NRF_GPIO->PIN_CNF[MOSI_Pin] = (GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos)
+                                        | (GPIO_PIN_CNF_DRIVE_S0S1 << GPIO_PIN_CNF_DRIVE_Pos)
+                                        | (GPIO_PIN_CNF_PULL_Disabled << GPIO_PIN_CNF_PULL_Pos)
+                                        | (GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos)
+                                        | (GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos);
+                                        
+        NRF_GPIO->PIN_CNF[MISO_Pin] = (GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos)
+                                        | (GPIO_PIN_CNF_DRIVE_S0S1 << GPIO_PIN_CNF_DRIVE_Pos)
+                                        | (GPIO_PIN_CNF_PULL_Disabled << GPIO_PIN_CNF_PULL_Pos)
+                                        | (GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos)
+                                        | (GPIO_PIN_CNF_DIR_Input << GPIO_PIN_CNF_DIR_Pos);                                     
+        spi->PSELSCK  = SCK_Pin;
+        spi->PSELMOSI = MOSI_Pin;
+        spi->PSELMISO = MISO_Pin;       
+        
+        setFrequency(SPI_1M);
+        setSPIMode(SPI_MODE3);
+        setBitORDER(MSBFIRST);
+        
+        spi->EVENTS_READY = 0;
+        spi->ENABLE = (SPI_ENABLE_ENABLE_Enabled << SPI_ENABLE_ENABLE_Pos);
+    
+}
+
+/**********************************************************************
+name :
+function : 
+**********************************************************************/
+void SPIClass::begin()
+{
+    begin(SCK, MOSI, MISO);
+}
+
+/**********************************************************************
+name :
+function : 
+**********************************************************************/
+uint8_t SPIClass::transfer(uint8_t data)
+{
+    while( spi->EVENTS_READY != 0U );
+    
+    spi->TXD = (uint32_t)data;
+    
+    while(spi->EVENTS_READY == 0);
+    
+    data = (uint8_t)spi->RXD;
+    
+    spi->EVENTS_READY = 0;
+    
+    return data;
+}
+
+/**********************************************************************
+name :
+function : 
+**********************************************************************/
+void SPIClass::endTransfer()
+{
+    spi->ENABLE = (SPI_ENABLE_ENABLE_Disabled << SPI_ENABLE_ENABLE_Pos);
+}
+
+/**********************************************************************
+name :
+function : 
+**********************************************************************/
+
+//SPIClass SPI(NRF_SPI1);
diff -r af76616e4d75 -r 4251b62991ac spi_master.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/spi_master.h	Tue May 16 19:31:49 2017 +0000
@@ -0,0 +1,84 @@
+/*
+
+Copyright (c) 2012-2014 RedBearLab
+
+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 _SPI_MASTER_H_
+#define _SPI_MASTER_H_
+
+#include "mbed.h"
+
+#define SPI_FREQUENCY_125K 0x02000000UL
+#define SPI_FREQUENCY_250K 0x04000000UL
+#define SPI_FREQUENCY_500K 0x08000000UL
+#define SPI_FREQUENCY_1M   0x10000000UL
+#define SPI_FREQUENCY_2M   0x20000000UL
+#define SPI_FREQUENCY_4M   0x40000000UL
+#define SPI_FREQUENCY_8M   0x80000000UL
+
+#define SPI_125K 0
+#define SPI_250K 1
+#define SPI_500K 2
+#define SPI_1M   3
+#define SPI_2M   4
+#define SPI_4M   5
+#define SPI_8M   6
+
+#define SPI_MODE0 0
+#define SPI_MODE1 1
+#define SPI_MODE2 2
+#define SPI_MODE3 3
+
+#define CS      P0_10
+#define SCK     P0_8
+#define MOSI    P0_9
+#define MISO    P0_11
+
+typedef enum{
+    
+    MSBFIRST = 0,
+    LSBFIRST = 1
+    
+}BitOrder;
+
+class SPIClass
+{
+    public:
+        SPIClass(NRF_SPI_Type *_spi);
+    
+        void begin();
+        void begin(uint32_t sck, uint32_t mosi, uint32_t miso);
+        uint8_t transfer(uint8_t data);
+        void endTransfer();
+            
+        void setSPIMode( uint8_t mode );
+        void setFrequency(uint8_t speed );
+        void setBitORDER( BitOrder  bit);
+        void setCPHA( bool trailing);
+        void setCPOL( bool active_low);
+        
+        
+    private:
+        NRF_SPI_Type *spi;
+        
+        uint32_t SCK_Pin;
+        uint32_t MOSI_Pin;
+        uint32_t MISO_Pin;
+
+};
+
+#endif