Bluetooth enabled control of a BLDC via the Allegro MicroSystems A4960.
Dependencies: BLE_API mbed nRF51822
Fork of BLE_ModularRobot by
Revision 11:4251b62991ac, committed 2017-05-16
- Comitter:
- anniemao
- Date:
- Tue May 16 19:31:49 2017 +0000
- Parent:
- 10:af76616e4d75
- Commit message:
- Annie Mao 2017
Changed in this revision
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