Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Revision 1:df1ae6d3fd03, committed 2018-11-13
- Comitter:
- lukofsky
- Date:
- Tue Nov 13 19:27:58 2018 +0000
- Parent:
- 0:15495bc2362a
- Commit message:
- Memulator;
Changed in this revision
--- a/main.cpp Tue Nov 13 01:28:09 2018 +0000 +++ b/main.cpp Tue Nov 13 19:27:58 2018 +0000 @@ -1,31 +1,488 @@ -#include "mbed.h" - -AnalogIn analog_value(A0); - -DigitalOut led(LED1); - -int main() -{ - float meas_r; - float meas_v; - - printf("\nAnalogIn example\n"); - - while(1) { - - meas_r = analog_value.read(); // Read the analog input value (value from 0.0 to 1.0 = full ADC conversion range) - meas_v = meas_r * 3300; // Converts value in the 0V-3.3V range - - // Display values - printf("measure = %f = %.0f mV\n", meas_r, meas_v); - - // LED is ON is the value is below 1V - if (meas_v < 1000) { - led = 1; // LED ON - } else { - led = 0; // LED OFF - } - - wait(1.0); // 1 second - } -} +/////////////////////////////////////////////////////////////////////////// +/** FS & SS EMULATOR CODE + * + * Version: 1.0 + * Author: Rachel Yang (Adapted by Patrick Doyle) + * Last Date Modified: 2018.10.2 + * + * Target Device: STM32F413 + * + * Description: + * digital filter for SS (2nd order) and FS (main peak only) + * + * Notes: + * uses 2 external ADCs (e.g. LTC1992) for FS & SS inputs + * uses internal TIM2 to precisely control sampling rate (fs) + * uses internal DACs to output single-ended FS & SS outputs + */ +/////////////////////////////////////////////////////////////////////////// + +#include "mbed.h" + +#ifdef __cplusplus +extern "C" +#endif + +#define TIM_USR TIM2 +#define TIM_USR_IRQ TIM2_IRQn + +// initialize serial debug (UART)?? +//Serial pc(PB_6, PB_8); // USBTX, USBRX + +// initialize SPI +SPI spi(NC, PA_12_ALT0, PB_0); // mosi, miso, sclk (corresponds to SPI5, default hardware connection) +//SPI spi(NC, PA_6, PB_3); // mosi, miso, sclk (corresponds to SPI1) +DigitalOut cs_fs(PB_1); // FS chip select +DigitalOut cs_ss(PA_9); // SS chip select + +// initialize LED (used as indicator to confirm code uploaded) +DigitalOut myled1(PB_9); // corresponds to LED1 (red on display emulator) + +// pin declarations +//AnalogIn input_pin(PC_0); // corresponds to A1 (A0 on F413ZH DISCO) +AnalogOut output_pin_n(PA_4); // HPZR SE output from MCU +AnalogOut output_pin_p(PA_5); // VPZR SE output from MCU + +// for internal input read +int outputimpulse = 1; + +// --- constants and global variables for SS --- + +// constants for transfer function for SS +// note: when extracting constants, having more decimal places is more accurate +// H(z) = a0 + a1*z^-1 + a2*z^-2 + a3*z^-3 + a4*z^-4 + a5*z^-5 +// ------------------------------------------------------ +// b0 + b1*z^-1 + b2*z^-2 + b3*z^-3 + b4*z^-4 + b5*z^-5 + +// for fs = 198 kHz: (samp_period = 20 with prescaler = 23) +//const float a0 = 2.347062E-05; +//const float a1 = 2.442144E-05; +//const float a2 = -4.408877E-05; +//const float a3 = -4.408877E-05; +//const float a4 = 2.442144E-05; +//const float a5 = 2.347062E-05; +//const float b0 = 1.0; +//const float b1 = -3.065112; +//const float b2 = 2.320246; +//const float b3 = 1.468017; +//const float b4 = -2.636283; +//const float b5 = 9.131404E-01; + +const float gain_adj_ss=-.4; //set gain adjustment to lock mirrors + +// for fs = 182 kHz: (samp_period = 21 with prescaler = 24) +float a0 = 2.790071E-5; +float a1 = 2.923599E-5; +float a2 = -5.179560E-5; +float a3 = -5.179560E-5; +float a4 = 2.923599E-5; +float a5 = 2.790071E-5; +float b0 = 1.0; +float b1 = -3.054730; +float b2 = 2.289613; +float b3 = 1.504730; +float b4 = -2.659329; +float b5 = 0.919726; + +// filter's input and output arrays + +int x_ss0 = 0; +int x_ss1 = 0; +int x_ss2 = 0; +int x_ss3 = 0; +int x_ss4 = 0; +int x_ss5 = 0; + + +float y_ss0 = 0; +float y_ss1 = 0; +float y_ss2 = 0; +float y_ss3 = 0; +float y_ss4 = 0; +float y_ss5 = 0; + +int i2 =0; + +// --- constants and global variables for FS --- + +// constants for transfer function for FS +// note: when extracting constants, having more decimal places is more accurate +// H(z) = c0 + c1*z^-1 + c2*z^-2 +// ------------------------ +// d0 + d1*z^-1 + d2*z^-2 + +// for fs = 198 kHz prewarped & scaled: (samp_period = 20 with prescaler = 23) +//const float c0 = 1.216980E-02; +//const float c1 = 0; +//const float c2 = -1.216980E-02; +//const float d0 = 1.0; +//const float d1 = -1.366137; +//const float d2 = 9.997566E-01; + + +//198kHz, Q = 1000 +//float c0 = 3.650050e-02; +//float c1 = 0; +//float c2 = -3.650050e-02; +//float d0 = 1; +//float d1 = -1.365804e+00; +//float d2 = 9.992700e-01; + +//198kHz, Q = 500 +//float c0 = 7.297437e-02; +//float c1 = 0; +//float c2 = -7.297437e-02; +//float d0 = 1; +//float d1 = -1.365306e+00; +//float d2 = 9.985405e-01; + +//198kHz, Q = 100 +//float c0 = 3.638099e-01; +//float c1 = 0; +//float c2 = -3.638099e-01; +//float d0 = 1; +//float d1 = -1.361332e+00; +//float d2 = 9.927238e-01; + +//198kHz, Q = 10 +//float c0 = 3.522754e+00; +//float c1 = 0; +//float c2 = -3.522754e+00; +//float d0 = 1; +//float d1 = -1.318172e+00; +//float d2 = 9.295449e-01; + + +//265kHz, Q = 3000 +//float c0 = 9.570427e-03; +//float c1 = 0; +//float c2 = -9.570427e-03; +//float d0 = 1; +//float d1 = -1.637160e+00; +//float d2 = 9.998086e-01; + +//265kHz, Q = 1000 +//float c0 = 2.870579e-02; +//float c1 = 0; +//float c2 = -2.870579e-02; +//float d0 = 1; +//float d1 = -1.636847e+00; +//float d2 = 9.994259e-01; + +//265kHz, Q = 500 +//float c0 = 5.739510e-02; +//float c1 = 0; +//float c2 = -5.739510e-02; +//float d0 = 1; +//float d1 = -1.636377e+00; +//float d2 = 9.988521e-01; + +//Elena's +// fr=2.8kHz, Q=1000, fs=277,778 z +//float c0 = 0.08273001473594155; +// +//float c1 = 0.16546002947188265; +// +//float c2 = 0.08273001473594155; +// +//float d0 = 1.0; +// +//float d1 = -1.6685290763800154; +// +//float d2 = 0.9994491353237815; + + +//@277,778 Hz Fs +//float c0 = 0.08274520854011191; +// +//float c1 = 0.16549041708022338; +// +//float c2 = 0.08274520854011225; +// +//float d0 = 1.0; +// +//float d1 = -1.6688355105577437; +// +//float d2 = 0.999816344718191; + +float gain_adj_fs= 2*2*(.25*(.5*(.5*(.25*.29))))/5;// (1/atteunation relative to 10x)(multiplier)(starting point) ///.9*.029; //set final gain adjustment to lock mirrors. Targets In/Out ratio of .82 @26kHz (to match Prototype) +//most stable prior to hpzr attenuator addition 2*(.25*(.5*(.5*(.25*.29))))/5; +//most stable in general, w/ attenuator 2*2*(.25*(.5*(.5*(.25*.29))))/5; + +//float gain_adj_fs=.002; + +// for fs = 182 kHz, Q=3000 prewarped & scaled: (samp_period = 21 with prescaler = 24) +//float c0 = 0.0129569; +//float c1 = 0; +//float c2 = -0.0129569; +//float d0 = 1.0; +//float d1 = -1.257566; +//float d2 = 0.999741; + + +// for fs = 182000, Q=100 +float c0 = 3.872520e-01; +float c1 = 0; +float c2 = -3.872520e-01; +float d0 = 1; +float d1 = -1.252858e+00; +float d2 = 9.922550e-01; + + +// filter's input and output arrays +int x_fs0 = 0; +int x_fs1 = 0; +int x_fs2 = 0; +int x_fs3 = 0; + +float y_fs0 = 0; +float y_fs1 = 0; +float y_fs2 = 0; +float y_fs3 = 0; + +// --- FUNCTIONS --- + +// --- functions for handling TIM2 initialization to control sampling rate --- + +//void SysTick_Handler(void) +//{ +// HAL_IncTick(); +// HAL_SYSTICK_IRQHandler(); +//} +// +//// --- end functions for TIM2 --- + + + +/** reads external ADC from SPI + * @param cs (chip select pin) + * @returns ADC input value (range from -2048 to 2047) + */ + +int input = 0; +int read_adc(DigitalOut cs){ + input = 0; + + // select external adc + cs = 0; + + // send dummy byte to receive ADC read + uint16_t adc_read = spi.write(0x0); +// pc.printf("ADC = %X ", adc_read); // for debug + + // deselect external adc + cs = 1; + + // bit shift adc_input for 12-bit resolution + uint16_t input_temp = adc_read >> 3; + + // convert uint16_t to int using two's complement for Differential ADC (not used anymore) +// if ((input_temp & 0x800) == 0x800) { // check if sign bit is raised (i.e. neg value) +// input_temp = ~(input_temp-1); // convert from two's complement form +// input = -1*(input_temp^0xF000); // mask input_temp for 12 bits & add sign back in +// } else { +// input = input_temp; // no action if sign bit is not raised (i.e. pos value) +// } + + + //Assuming non-differential ADC (AD7046) + input = input_temp; // no action if sign bit is not raised (i.e. pos value) + + return input; +} + +/** computes and writes SS output to DAC based on SS difference eqn using ADC input + * @returns none + */ +void compute_ss_output(){ + + // shift inputs for new time step + x_ss5 = x_ss4; // x[n-4] --> x[n-5] + x_ss4 = x_ss3; // x[n-3] --> x[n-4] + x_ss3 = x_ss2; // x[n-2] --> x[n-3] + x_ss2 = x_ss1; // x[n-1] --> x[n-2] + x_ss1 = x_ss0; // x[n] --> x[n-1] + + //shift outputs for new time step + y_ss5 = y_ss4; // y[n-4] --> y[n-5] + y_ss4 = y_ss3; // y[n-3] --> y[n-4] + y_ss3 = y_ss2; // y[n-2] --> y[n-3] + y_ss2 = y_ss1; // y[n-1] --> y[n-2] + y_ss1 = y_ss0; // y[n] --> y[n-1] + + // read input x[n] from SS DRV P + x_ss0 = read_adc(cs_ss); // value from 0 to 4095 for 12-bit ADC +// pc.printf("ADC = %d ", x_ss[0]); // for debug + + // for verifying impulse response + // "read" input x[n] (internal input read) +// if (outputimpulse > 0) { +// x_ss[0] = 2047; +// outputimpulse = outputimpulse - 1; +// } else { +// x_ss[0] = 0; +// } + + // calculate output y[n] (need intermediary computations to prevent overflow) + float xterms = a0*x_ss0+a1*x_ss1+a2*x_ss2+a3*x_ss3+a4*x_ss4+a5*x_ss5; + float yterms = b1*y_ss1+b2*y_ss2+b3*y_ss3+b4*y_ss4+b5*y_ss5; + y_ss0 = (xterms - yterms); // *1/b0 + +// pc.printf("xterms = %f ", xterms); +// pc.printf("yterms = %f ", yterms); +// pc.printf("y[0] = %f ", y[0]); + + // --- for writing DAC output directly to register --- + + // scale y[n], then bias y[n] at VCC/2 = 1.25V and scale gain + uint16_t output = (uint16_t) (gain_adj_ss*y_ss0+2048); +// pc.printf(" %d ",output); + + // set DAC output by writing directly to register (pin PA_5) + // note: DAC register takes in unsigned 12-bit (i.e. 0 to 4096) + DAC->DHR12R2 = output; + + + + // - end - + // myled1 = !myled1; +} + +/** computes and writes FS output to DAC based on FS difference eqn using ADC input + * @returns none + */ + + uint16_t output=2048; +void compute_fs_output(){ + //myled1 = !myled1; + DAC->DHR12R1 = output; + // myled1 = !myled1; + // shift inputs for new time step + x_fs2 = x_fs1; // x[n-1] --> x[n-2] + x_fs1 = x_fs0; // x[n] --> x[n-1] + + //shift outputs for new time step + y_fs2 = y_fs1; // y[n-1] --> y[n-2] + y_fs1 = y_fs0; // y[n] --> y[n-1] + + // read input x[n] - ONLY READ FROM OUTPUT_P (not N) + x_fs0 = read_adc(cs_fs); // value from -2048 to 2047 for 12-bit ADC +// pc.printf("ADC = %d ", x_fs[0]); // for debug + //DAC->DHR12R1 = (uint16_t) (x_fs[0]); //debug + + + + // calculate output y[n] (need intermediary computations to prevent overflow) +// float xterms = c0*x_fs[0]+c1*x_fs[1]+c2*x_fs[2]; // explicit c1 = 0 + float xterms = c0*x_fs0+c2*x_fs2; // implicit c1 = 0 + float yterms = d1*y_fs1+d2*y_fs2; + y_fs0 = (xterms - yterms); // *1/d0 + + + + + // --- for writing DAC output directly to register --- + + // scale y[n], then bias y[n] at VCC/2 = 1.25V and scale gain + output = (uint16_t) (gain_adj_fs*y_fs0+2048); +// pc.printf(" %d ",output); + + + // set DAC output by writing directly to register (pin PA_4) + // note: DAC register takes in unsigned 12-bit (i.e. 0 to 4096) + //DAC->DHR12R1 = output; + + +} + + + + +TIM_HandleTypeDef mTimUserHandle; + int iteration1=0; + int iteration2=0; +extern "C" +void M_TIM_USR_Handler(void) { + //myled1 = 0;//!myled1; + + if (__HAL_TIM_GET_FLAG(&mTimUserHandle, TIM_FLAG_UPDATE) == SET) { + + myled1 = 1;//!myled1; + __HAL_TIM_CLEAR_FLAG(&mTimUserHandle, TIM_FLAG_UPDATE); + + //for(int i = 0; i < 17; i++){ + // myled1 = !myled1; + + + // } + + compute_fs_output(); + compute_ss_output(); + myled1=0; + + //if (__HAL_TIM_GET_FLAG(&mTimUserHandle, TIM_FLAG_UPDATE) == SET) { +// myled1 = !myled1; +// } + } +} + + +int main() +{ + // set serial debug baud rate + // pc.baud(9600); + + // deselect external adcs + cs_ss = 1; + cs_fs = 1; + + // set up spi + spi.format(16,3); + spi.frequency(50000000); // 50MHz (fastest possible with ADC) + + // LED sequence to indicate code uploaded + for(int i = 0; i < 10; i++){ + myled1 = i & 0x1; + wait(0.1); + } + + + // initialize timer TIM2 + __HAL_RCC_TIM2_CLK_ENABLE(); + + mTimUserHandle.Instance = TIM_USR; + mTimUserHandle.Init.Prescaler = 0; + mTimUserHandle.Init.CounterMode = TIM_COUNTERMODE_UP; + mTimUserHandle.Init.Period = 549; //549 FOR 182KHz //504 for 198kHz, 359 for 277khz + mTimUserHandle.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; + HAL_TIM_Base_Init(&mTimUserHandle); + HAL_TIM_Base_Start_IT(&mTimUserHandle); + + NVIC_SetVector(TIM_USR_IRQ, (uint32_t)M_TIM_USR_Handler); + NVIC_EnableIRQ(TIM_USR_IRQ); + + + //pc.printf("\nstarting ss_rlc\n"); + + // to read system clock (max at 100MHz) +// SystemCoreClock = 125000000; // set CPU clk (can overclock to 125MHz max) + //pc.printf("SystemCoreClock = %d", SystemCoreClock); +// +//uint16_t dac_out=0; +//uint16_t output = (uint16_t) (4000); + while(1) { + myled1 = 1; + myled1 = 0; + + + + //myled1=!myled1; + // DAC->DHR12R1 = output; + + + + + + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mySPI/mySPI.cpp Tue Nov 13 19:27:58 2018 +0000 @@ -0,0 +1,557 @@ +//////////////////////////////////////////////////////////////////////// +// NOTE: two changes +// (1) include "mySPI.h" instead of "SPI.h" +// (2) commented out lock, _acquire, and unlock from the write method +//////////////////////////////////////////////////////////////////////// + +/* mbed Microcontroller Library + + * Copyright (c) 2006-2013 ARM Limited + + * + + * Licensed under the Apache License, Version 2.0 (the "License"); + + * you may not use this file except in compliance with the License. + + * You may obtain a copy of the License at + + * + + * http://www.apache.org/licenses/LICENSE-2.0 + + * + + * Unless required by applicable law or agreed to in writing, software + + * distributed under the License is distributed on an "AS IS" BASIS, + + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + + * See the License for the specific language governing permissions and + + * limitations under the License. + + */ + +// include custom SPI header file instead of default SPI header file +//#include "drivers/SPI.h" +#include "mySPI.h" + +#include "platform/mbed_critical.h" + + + +#if DEVICE_SPI_ASYNCH + +#include "platform/mbed_power_mgmt.h" + +#endif + + + +#if DEVICE_SPI + + + +namespace mbed { + + + +#if DEVICE_SPI_ASYNCH && TRANSACTION_QUEUE_SIZE_SPI + +CircularBuffer<Transaction<SPI>, TRANSACTION_QUEUE_SIZE_SPI> SPI::_transaction_buffer; + +#endif + + + +SPI::SPI(PinName mosi, PinName miso, PinName sclk, PinName ssel) : + + _spi(), + +#if DEVICE_SPI_ASYNCH + + _irq(this), + + _usage(DMA_USAGE_NEVER), + + _deep_sleep_locked(false), + +#endif + + _bits(8), + + _mode(0), + + _hz(1000000), + + _write_fill(SPI_FILL_CHAR) + +{ + + // No lock needed in the constructor + + + + spi_init(&_spi, mosi, miso, sclk, ssel); + + _acquire(); + +} + + + +void SPI::format(int bits, int mode) + +{ + + lock(); + + _bits = bits; + + _mode = mode; + + // If changing format while you are the owner then just + + // update format, but if owner is changed then even frequency should be + + // updated which is done by acquire. + + if (_owner == this) { + + spi_format(&_spi, _bits, _mode, 0); + + } else { + + _acquire(); + + } + + unlock(); + +} + + + +void SPI::frequency(int hz) + +{ + + lock(); + + _hz = hz; + + // If changing format while you are the owner then just + + // update frequency, but if owner is changed then even frequency should be + + // updated which is done by acquire. + + if (_owner == this) { + + spi_frequency(&_spi, _hz); + + } else { + + _acquire(); + + } + + unlock(); + +} + + + +SPI *SPI::_owner = NULL; + +SingletonPtr<PlatformMutex> SPI::_mutex; + + + +// ignore the fact there are multiple physical spis, and always update if it wasn't us last + +void SPI::aquire() + +{ + + lock(); + + if (_owner != this) { + + spi_format(&_spi, _bits, _mode, 0); + + spi_frequency(&_spi, _hz); + + _owner = this; + + } + + unlock(); + +} + + + +// Note: Private function with no locking + +void SPI::_acquire() + +{ + + if (_owner != this) { + + spi_format(&_spi, _bits, _mode, 0); + + spi_frequency(&_spi, _hz); + + _owner = this; + + } + +} + + + +int SPI::write(int value) + +{ + +// lock(); + +// _acquire(); + + int ret = spi_master_write(&_spi, value); + +// unlock(); + + return ret; + +} + + + +int SPI::write(const char *tx_buffer, int tx_length, char *rx_buffer, int rx_length) + +{ + + lock(); + + _acquire(); + + int ret = spi_master_block_write(&_spi, tx_buffer, tx_length, rx_buffer, rx_length, _write_fill); + + unlock(); + + return ret; + +} + + + +void SPI::lock() + +{ + + _mutex->lock(); + +} + + + +void SPI::unlock() + +{ + + _mutex->unlock(); + +} + + + +void SPI::set_default_write_value(char data) + +{ + + lock(); + + _write_fill = data; + + unlock(); + +} + + + +#if DEVICE_SPI_ASYNCH + + + +int SPI::transfer(const void *tx_buffer, int tx_length, void *rx_buffer, int rx_length, unsigned char bit_width, const event_callback_t &callback, int event) + +{ + + if (spi_active(&_spi)) { + + return queue_transfer(tx_buffer, tx_length, rx_buffer, rx_length, bit_width, callback, event); + + } + + start_transfer(tx_buffer, tx_length, rx_buffer, rx_length, bit_width, callback, event); + + return 0; + +} + + + +void SPI::abort_transfer() + +{ + + spi_abort_asynch(&_spi); + + unlock_deep_sleep(); + +#if TRANSACTION_QUEUE_SIZE_SPI + + dequeue_transaction(); + +#endif + +} + + + + + +void SPI::clear_transfer_buffer() + +{ + +#if TRANSACTION_QUEUE_SIZE_SPI + + _transaction_buffer.reset(); + +#endif + +} + + + +void SPI::abort_all_transfers() + +{ + + clear_transfer_buffer(); + + abort_transfer(); + +} + + + +int SPI::set_dma_usage(DMAUsage usage) + +{ + + if (spi_active(&_spi)) { + + return -1; + + } + + _usage = usage; + + return 0; + +} + + + +int SPI::queue_transfer(const void *tx_buffer, int tx_length, void *rx_buffer, int rx_length, unsigned char bit_width, const event_callback_t &callback, int event) + +{ + +#if TRANSACTION_QUEUE_SIZE_SPI + + transaction_t t; + + + + t.tx_buffer = const_cast<void *>(tx_buffer); + + t.tx_length = tx_length; + + t.rx_buffer = rx_buffer; + + t.rx_length = rx_length; + + t.event = event; + + t.callback = callback; + + t.width = bit_width; + + Transaction<SPI> transaction(this, t); + + if (_transaction_buffer.full()) { + + return -1; // the buffer is full + + } else { + + core_util_critical_section_enter(); + + _transaction_buffer.push(transaction); + + if (!spi_active(&_spi)) { + + dequeue_transaction(); + + } + + core_util_critical_section_exit(); + + return 0; + + } + +#else + + return -1; + +#endif + +} + + + +void SPI::start_transfer(const void *tx_buffer, int tx_length, void *rx_buffer, int rx_length, unsigned char bit_width, const event_callback_t &callback, int event) + +{ + + lock_deep_sleep(); + + _acquire(); + + _callback = callback; + + _irq.callback(&SPI::irq_handler_asynch); + + spi_master_transfer(&_spi, tx_buffer, tx_length, rx_buffer, rx_length, bit_width, _irq.entry(), event, _usage); + +} + + + +void SPI::lock_deep_sleep() + +{ + + if (_deep_sleep_locked == false) { + + sleep_manager_lock_deep_sleep(); + + _deep_sleep_locked = true; + + } + +} + + + +void SPI::unlock_deep_sleep() + +{ + + if (_deep_sleep_locked == true) { + + sleep_manager_unlock_deep_sleep(); + + _deep_sleep_locked = false; + + } + +} + + + +#if TRANSACTION_QUEUE_SIZE_SPI + + + +void SPI::start_transaction(transaction_t *data) + +{ + + start_transfer(data->tx_buffer, data->tx_length, data->rx_buffer, data->rx_length, data->width, data->callback, data->event); + +} + + + +void SPI::dequeue_transaction() + +{ + + Transaction<SPI> t; + + if (_transaction_buffer.pop(t)) { + + SPI *obj = t.get_object(); + + transaction_t *data = t.get_transaction(); + + obj->start_transaction(data); + + } + +} + + + +#endif + + + +void SPI::irq_handler_asynch(void) + +{ + + int event = spi_irq_handler_asynch(&_spi); + + if (_callback && (event & SPI_EVENT_ALL)) { + + unlock_deep_sleep(); + + _callback.call(event & SPI_EVENT_ALL); + + } + +#if TRANSACTION_QUEUE_SIZE_SPI + + if (event & (SPI_EVENT_ALL | SPI_EVENT_INTERNAL_TRANSFER_COMPLETE)) { + + // SPI peripheral is free (event happened), dequeue transaction + + dequeue_transaction(); + + } + +#endif + +} + + + +#endif + + + +} // namespace mbed + + + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mySPI/mySPI.h Tue Nov 13 19:27:58 2018 +0000 @@ -0,0 +1,621 @@ +//////////////////////////////////////////////////////////////////////// +// NOTE: no change +//////////////////////////////////////////////////////////////////////// + +/* mbed Microcontroller Library + + * Copyright (c) 2006-2015 ARM Limited + + * + + * Licensed under the Apache License, Version 2.0 (the "License"); + + * you may not use this file except in compliance with the License. + + * You may obtain a copy of the License at + + * + + * http://www.apache.org/licenses/LICENSE-2.0 + + * + + * Unless required by applicable law or agreed to in writing, software + + * distributed under the License is distributed on an "AS IS" BASIS, + + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + + * See the License for the specific language governing permissions and + + * limitations under the License. + + */ + +#ifndef MBED_SPI_H + +#define MBED_SPI_H + + + +#include "platform/platform.h" + + + +#if defined (DEVICE_SPI) || defined(DOXYGEN_ONLY) + + + +#include "platform/PlatformMutex.h" + +#include "hal/spi_api.h" + +#include "platform/SingletonPtr.h" + +#include "platform/NonCopyable.h" + + + +#if DEVICE_SPI_ASYNCH + +#include "platform/CThunk.h" + +#include "hal/dma_api.h" + +#include "platform/CircularBuffer.h" + +#include "platform/FunctionPointer.h" + +#include "platform/Transaction.h" + +#endif + + + +namespace mbed { + +/** \addtogroup drivers */ + + + +/** A SPI Master, used for communicating with SPI slave devices + + * + + * The default format is set to 8-bits, mode 0, and a clock frequency of 1MHz + + * + + * Most SPI devices will also require Chip Select and Reset signals. These + + * can be controlled using DigitalOut pins + + * + + * @note Synchronization level: Thread safe + + * + + * Example: + + * @code + + * // Send a byte to a SPI slave, and record the response + + * + + * #include "mbed.h" + + * + + * // hardware ssel (where applicable) + + * //SPI device(p5, p6, p7, p8); // mosi, miso, sclk, ssel + + * + + * // software ssel + + * SPI device(p5, p6, p7); // mosi, miso, sclk + + * DigitalOut cs(p8); // ssel + + * + + * int main() { + + * // hardware ssel (where applicable) + + * //int response = device.write(0xFF); + + * + + * device.lock(); + + * // software ssel + + * cs = 0; + + * int response = device.write(0xFF); + + * cs = 1; + + * device.unlock(); + + * + + * } + + * @endcode + + * @ingroup drivers + + */ + +class SPI : private NonCopyable<SPI> { + + + +public: + + + + /** Create a SPI master connected to the specified pins + + * + + * mosi or miso can be specified as NC if not used + + * + + * @param mosi SPI Master Out, Slave In pin + + * @param miso SPI Master In, Slave Out pin + + * @param sclk SPI Clock pin + + * @param ssel SPI chip select pin + + */ + + SPI(PinName mosi, PinName miso, PinName sclk, PinName ssel = NC); + + + + /** Configure the data transmission format + + * + + * @param bits Number of bits per SPI frame (4 - 16) + + * @param mode Clock polarity and phase mode (0 - 3) + + * + + * @code + + * mode | POL PHA + + * -----+-------- + + * 0 | 0 0 + + * 1 | 0 1 + + * 2 | 1 0 + + * 3 | 1 1 + + * @endcode + + */ + + void format(int bits, int mode = 0); + + + + /** Set the spi bus clock frequency + + * + + * @param hz SCLK frequency in hz (default = 1MHz) + + */ + + void frequency(int hz = 1000000); + + + + /** Write to the SPI Slave and return the response + + * + + * @param value Data to be sent to the SPI slave + + * + + * @returns + + * Response from the SPI slave + + */ + + virtual int write(int value); + + + + /** Write to the SPI Slave and obtain the response + + * + + * The total number of bytes sent and received will be the maximum of + + * tx_length and rx_length. The bytes written will be padded with the + + * value 0xff. + + * + + * @param tx_buffer Pointer to the byte-array of data to write to the device + + * @param tx_length Number of bytes to write, may be zero + + * @param rx_buffer Pointer to the byte-array of data to read from the device + + * @param rx_length Number of bytes to read, may be zero + + * @returns + + * The number of bytes written and read from the device. This is + + * maximum of tx_length and rx_length. + + */ + + virtual int write(const char *tx_buffer, int tx_length, char *rx_buffer, int rx_length); + + + + /** Acquire exclusive access to this SPI bus + + */ + + virtual void lock(void); + + + + /** Release exclusive access to this SPI bus + + */ + + virtual void unlock(void); + + + + /** Set default write data + + * SPI requires the master to send some data during a read operation. + + * Different devices may require different default byte values. + + * For example: A SD Card requires default bytes to be 0xFF. + + * + + * @param data Default character to be transmitted while read operation + + */ + + void set_default_write_value(char data); + + + +#if DEVICE_SPI_ASYNCH + + + + /** Start non-blocking SPI transfer using 8bit buffers. + + * + + * This function locks the deep sleep until any event has occurred + + * + + * @param tx_buffer The TX buffer with data to be transfered. If NULL is passed, + + * the default SPI value is sent + + * @param tx_length The length of TX buffer in bytes + + * @param rx_buffer The RX buffer which is used for received data. If NULL is passed, + + * received data are ignored + + * @param rx_length The length of RX buffer in bytes + + * @param callback The event callback function + + * @param event The logical OR of events to modify. Look at spi hal header file for SPI events. + + * @return Zero if the transfer has started, or -1 if SPI peripheral is busy + + */ + + template<typename Type> + + int transfer(const Type *tx_buffer, int tx_length, Type *rx_buffer, int rx_length, const event_callback_t &callback, int event = SPI_EVENT_COMPLETE) + + { + + if (spi_active(&_spi)) { + + return queue_transfer(tx_buffer, tx_length, rx_buffer, rx_length, sizeof(Type) * 8, callback, event); + + } + + start_transfer(tx_buffer, tx_length, rx_buffer, rx_length, sizeof(Type) * 8, callback, event); + + return 0; + + } + + + + /** Abort the on-going SPI transfer, and continue with transfer's in the queue if any. + + */ + + void abort_transfer(); + + + + /** Clear the transaction buffer + + */ + + void clear_transfer_buffer(); + + + + /** Clear the transaction buffer and abort on-going transfer. + + */ + + void abort_all_transfers(); + + + + /** Configure DMA usage suggestion for non-blocking transfers + + * + + * @param usage The usage DMA hint for peripheral + + * @return Zero if the usage was set, -1 if a transaction is on-going + + */ + + int set_dma_usage(DMAUsage usage); + + + +protected: + + /** SPI IRQ handler + + * + + */ + + void irq_handler_asynch(void); + + + + /** Common transfer method + + * + + * @param tx_buffer The TX buffer with data to be transfered. If NULL is passed, + + * the default SPI value is sent + + * @param tx_length The length of TX buffer in bytes + + * @param rx_buffer The RX buffer which is used for received data. If NULL is passed, + + * received data are ignored + + * @param rx_length The length of RX buffer in bytes + + * @param bit_width The buffers element width + + * @param callback The event callback function + + * @param event The logical OR of events to modify + + * @return Zero if the transfer has started or was added to the queue, or -1 if SPI peripheral is busy/buffer is full + + */ + + int transfer(const void *tx_buffer, int tx_length, void *rx_buffer, int rx_length, unsigned char bit_width, const event_callback_t &callback, int event); + + + + /** + + * + + * @param tx_buffer The TX buffer with data to be transfered. If NULL is passed, + + * the default SPI value is sent + + * @param tx_length The length of TX buffer in bytes + + * @param rx_buffer The RX buffer which is used for received data. If NULL is passed, + + * received data are ignored + + * @param rx_length The length of RX buffer in bytes + + * @param bit_width The buffers element width + + * @param callback The event callback function + + * @param event The logical OR of events to modify + + * @return Zero if a transfer was added to the queue, or -1 if the queue is full + + */ + + int queue_transfer(const void *tx_buffer, int tx_length, void *rx_buffer, int rx_length, unsigned char bit_width, const event_callback_t &callback, int event); + + + + /** Configures a callback, spi peripheral and initiate a new transfer + + * + + * @param tx_buffer The TX buffer with data to be transfered. If NULL is passed, + + * the default SPI value is sent + + * @param tx_length The length of TX buffer in bytes + + * @param rx_buffer The RX buffer which is used for received data. If NULL is passed, + + * received data are ignored + + * @param rx_length The length of RX buffer in bytes + + * @param bit_width The buffers element width + + * @param callback The event callback function + + * @param event The logical OR of events to modify + + */ + + void start_transfer(const void *tx_buffer, int tx_length, void *rx_buffer, int rx_length, unsigned char bit_width, const event_callback_t &callback, int event); + + + +private: + + /** Lock deep sleep only if it is not yet locked */ + + void lock_deep_sleep(); + + + + /** Unlock deep sleep in case it is locked */ + + void unlock_deep_sleep(); + + + + + +#if TRANSACTION_QUEUE_SIZE_SPI + + + + /** Start a new transaction + + * + + * @param data Transaction data + + */ + + void start_transaction(transaction_t *data); + + + + /** Dequeue a transaction + + * + + */ + + void dequeue_transaction(); + + static CircularBuffer<Transaction<SPI>, TRANSACTION_QUEUE_SIZE_SPI> _transaction_buffer; + +#endif + + + +#endif + + + +public: + + virtual ~SPI() + + { + + } + + + +protected: + + spi_t _spi; + + + +#if DEVICE_SPI_ASYNCH + + CThunk<SPI> _irq; + + event_callback_t _callback; + + DMAUsage _usage; + + bool _deep_sleep_locked; + +#endif + + + + void aquire(void); + + static SPI *_owner; + + static SingletonPtr<PlatformMutex> _mutex; + + int _bits; + + int _mode; + + int _hz; + + char _write_fill; + + + +private: + + /* Private acquire function without locking/unlocking + + * Implemented in order to avoid duplicate locking and boost performance + + */ + + void _acquire(void); + +}; + + + +} // namespace mbed + + + +#endif + + + +#endif