Kenji Arai / mbed-os_TYBLE16

Dependents:   TYBLE16_simple_data_logger TYBLE16_MP3_Air

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers QSPI.cpp Source File

QSPI.cpp

00001 /* mbed Microcontroller Library
00002  * Copyright (c) 2006-2018 ARM Limited
00003  * SPDX-License-Identifier: Apache-2.0
00004  *
00005  * Licensed under the Apache License, Version 2.0 (the "License");
00006  * you may not use this file except in compliance with the License.
00007  * You may obtain a copy of the License at
00008  *
00009  *     http://www.apache.org/licenses/LICENSE-2.0
00010  *
00011  * Unless required by applicable law or agreed to in writing, software
00012  * distributed under the License is distributed on an "AS IS" BASIS,
00013  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00014  * See the License for the specific language governing permissions and
00015  * limitations under the License.
00016  */
00017 
00018 #include "drivers/QSPI.h"
00019 #include "platform/mbed_critical.h"
00020 #include <string.h>
00021 
00022 #if DEVICE_QSPI
00023 
00024 namespace mbed {
00025 
00026 QSPI *QSPI::_owner = NULL;
00027 SingletonPtr<PlatformMutex>  QSPI::_mutex;
00028 
00029 uint8_t convert_bus_width_to_line_count(qspi_bus_width_t width)
00030 {
00031     switch (width) {
00032         case QSPI_CFG_BUS_SINGLE:
00033             return 1;
00034         case QSPI_CFG_BUS_DUAL:
00035             return 2;
00036         case QSPI_CFG_BUS_QUAD:
00037             return 4;
00038         default:
00039             // Unrecognized bus width
00040             return 0;
00041     }
00042 }
00043 
00044 QSPI::QSPI(PinName io0, PinName io1, PinName io2, PinName io3, PinName sclk, PinName ssel, int mode) : _qspi()
00045 {
00046     _qspi_io0 = io0;
00047     _qspi_io1 = io1;
00048     _qspi_io2 = io2;
00049     _qspi_io3 = io3;
00050     _qspi_clk = sclk;
00051     _qspi_cs = ssel;
00052     _static_pinmap = NULL;
00053     _inst_width = QSPI_CFG_BUS_SINGLE;
00054     _address_width = QSPI_CFG_BUS_SINGLE;
00055     _address_size = QSPI_CFG_ADDR_SIZE_24;
00056     _alt_width = QSPI_CFG_BUS_SINGLE;
00057     _alt_size = 0;
00058     _data_width = QSPI_CFG_BUS_SINGLE;
00059     _num_dummy_cycles = 0;
00060     _mode = mode;
00061     _hz = ONE_MHZ;
00062     _initialized = false;
00063     _init_func = &QSPI::_initialize;
00064 
00065     //Go ahead init the device here with the default config
00066     bool success = (this->*_init_func)();
00067     MBED_ASSERT(success);
00068 }
00069 
00070 QSPI::QSPI(const qspi_pinmap_t &pinmap, int mode) : _qspi()
00071 {
00072     _qspi_io0 = pinmap.data0_pin;
00073     _qspi_io1 = pinmap.data1_pin;
00074     _qspi_io2 = pinmap.data2_pin;
00075     _qspi_io3 = pinmap.data3_pin;
00076     _qspi_clk = pinmap.sclk_pin;
00077     _qspi_cs = pinmap.ssel_pin;
00078     _static_pinmap = &pinmap;
00079     _inst_width = QSPI_CFG_BUS_SINGLE;
00080     _address_width = QSPI_CFG_BUS_SINGLE;
00081     _address_size = QSPI_CFG_ADDR_SIZE_24;
00082     _alt_width = QSPI_CFG_BUS_SINGLE;
00083     _alt_size = QSPI_CFG_ALT_SIZE_8;
00084     _data_width = QSPI_CFG_BUS_SINGLE;
00085     _num_dummy_cycles = 0;
00086     _mode = mode;
00087     _hz = ONE_MHZ;
00088     _initialized = false;
00089     _init_func = &QSPI::_initialize_direct;
00090 
00091     //Go ahead init the device here with the default config
00092     bool success = (this->*_init_func)();
00093     MBED_ASSERT(success);
00094 }
00095 
00096 qspi_status_t QSPI::configure_format(qspi_bus_width_t inst_width, qspi_bus_width_t address_width, qspi_address_size_t address_size, qspi_bus_width_t alt_width, qspi_alt_size_t alt_size, qspi_bus_width_t data_width, int dummy_cycles)
00097 {
00098     // Check that alt_size/alt_width are a valid combination
00099     uint8_t alt_lines = convert_bus_width_to_line_count(alt_width);
00100     if (alt_lines == 0) {
00101         return QSPI_STATUS_ERROR;
00102     } else if (alt_size % alt_lines != 0) {
00103         // Invalid alt size/width combination (alt size is not a multiple of the number of bus lines used to transmit it)
00104         return QSPI_STATUS_ERROR;
00105     }
00106 
00107     lock();
00108     _inst_width = inst_width;
00109     _address_width = address_width;
00110     _address_size = address_size;
00111     _alt_width = alt_width;
00112     _alt_size = alt_size;
00113     _data_width = data_width;
00114     _num_dummy_cycles = dummy_cycles;
00115     unlock();
00116 
00117     return QSPI_STATUS_OK;
00118 }
00119 
00120 qspi_status_t QSPI::set_frequency(int hz)
00121 {
00122     qspi_status_t ret_status = QSPI_STATUS_OK;
00123 
00124     if (_initialized) {
00125         lock();
00126         _hz = hz;
00127         //If the same owner, just change freq.
00128         //Otherwise we may have to change mode as well, so call _acquire
00129         if (_owner == this) {
00130             if (QSPI_STATUS_OK != qspi_frequency(&_qspi, _hz)) {
00131                 ret_status = QSPI_STATUS_ERROR;
00132             }
00133         } else {
00134             _acquire();
00135         }
00136         unlock();
00137     } else {
00138         ret_status = QSPI_STATUS_ERROR;
00139     }
00140 
00141     return ret_status;
00142 }
00143 
00144 qspi_status_t QSPI::read(int address, char *rx_buffer, size_t *rx_length)
00145 {
00146     qspi_status_t ret_status = QSPI_STATUS_ERROR;
00147 
00148     if (_initialized) {
00149         if ((rx_length != NULL) && (rx_buffer != NULL)) {
00150             if (*rx_length != 0) {
00151                 lock();
00152                 if (true == _acquire()) {
00153                     _build_qspi_command(QSPI_NO_INST, address, -1);
00154                     if (QSPI_STATUS_OK == qspi_read(&_qspi, &_qspi_command, rx_buffer, rx_length)) {
00155                         ret_status = QSPI_STATUS_OK;
00156                     }
00157                 }
00158                 unlock();
00159             }
00160         } else {
00161             ret_status = QSPI_STATUS_INVALID_PARAMETER;
00162         }
00163     }
00164 
00165     return ret_status;
00166 }
00167 
00168 qspi_status_t QSPI::write(int address, const char *tx_buffer, size_t *tx_length)
00169 {
00170     qspi_status_t ret_status = QSPI_STATUS_ERROR;
00171 
00172     if (_initialized) {
00173         if ((tx_length != NULL) && (tx_buffer != NULL)) {
00174             if (*tx_length != 0) {
00175                 lock();
00176                 if (true == _acquire()) {
00177                     _build_qspi_command(QSPI_NO_INST, address, -1);
00178                     if (QSPI_STATUS_OK == qspi_write(&_qspi, &_qspi_command, tx_buffer, tx_length)) {
00179                         ret_status = QSPI_STATUS_OK;
00180                     }
00181                 }
00182                 unlock();
00183             }
00184         } else {
00185             ret_status = QSPI_STATUS_INVALID_PARAMETER;
00186         }
00187     }
00188 
00189     return ret_status;
00190 }
00191 
00192 qspi_status_t QSPI::read(qspi_inst_t instruction, int alt, int address, char *rx_buffer, size_t *rx_length)
00193 {
00194     qspi_status_t ret_status = QSPI_STATUS_ERROR;
00195 
00196     if (_initialized) {
00197         if ((rx_length != NULL) && (rx_buffer != NULL)) {
00198             if (*rx_length != 0) {
00199                 lock();
00200                 if (true == _acquire()) {
00201                     _build_qspi_command(instruction, address, alt);
00202                     if (QSPI_STATUS_OK == qspi_read(&_qspi, &_qspi_command, rx_buffer, rx_length)) {
00203                         ret_status = QSPI_STATUS_OK;
00204                     }
00205                 }
00206                 unlock();
00207             }
00208         } else {
00209             ret_status = QSPI_STATUS_INVALID_PARAMETER;
00210         }
00211     }
00212 
00213     return ret_status;
00214 }
00215 
00216 qspi_status_t QSPI::write(qspi_inst_t instruction, int alt, int address, const char *tx_buffer, size_t *tx_length)
00217 {
00218     qspi_status_t ret_status = QSPI_STATUS_ERROR;
00219 
00220     if (_initialized) {
00221         if ((tx_length != NULL) && (tx_buffer != NULL)) {
00222             if (*tx_length != 0) {
00223                 lock();
00224                 if (true == _acquire()) {
00225                     _build_qspi_command(instruction, address, alt);
00226                     if (QSPI_STATUS_OK == qspi_write(&_qspi, &_qspi_command, tx_buffer, tx_length)) {
00227                         ret_status = QSPI_STATUS_OK;
00228                     }
00229                 }
00230                 unlock();
00231             }
00232         } else {
00233             ret_status = QSPI_STATUS_INVALID_PARAMETER;
00234         }
00235     }
00236 
00237     return ret_status;
00238 }
00239 
00240 qspi_status_t QSPI::command_transfer(qspi_inst_t instruction, int address, const char *tx_buffer, size_t tx_length, const char *rx_buffer, size_t rx_length)
00241 {
00242     qspi_status_t ret_status = QSPI_STATUS_ERROR;
00243 
00244     if (_initialized) {
00245         lock();
00246         if (true == _acquire()) {
00247             _build_qspi_command(instruction, address, -1); //We just need the command
00248             if (QSPI_STATUS_OK == qspi_command_transfer(&_qspi, &_qspi_command, (const void *)tx_buffer, tx_length, (void *)rx_buffer, rx_length)) {
00249                 ret_status = QSPI_STATUS_OK;
00250             }
00251         }
00252         unlock();
00253     }
00254 
00255     return ret_status;
00256 }
00257 
00258 void QSPI::lock()
00259 {
00260     _mutex->lock();
00261 }
00262 
00263 void QSPI::unlock()
00264 {
00265     _mutex->unlock();
00266 }
00267 
00268 // Note: Private helper function to initialize qspi HAL
00269 bool QSPI::_initialize()
00270 {
00271     if (_mode != 0 && _mode != 1) {
00272         _initialized = false;
00273         return _initialized;
00274     }
00275 
00276     qspi_status_t ret = qspi_init(&_qspi, _qspi_io0, _qspi_io1, _qspi_io2, _qspi_io3, _qspi_clk, _qspi_cs, _hz, _mode);
00277     if (QSPI_STATUS_OK == ret) {
00278         _initialized = true;
00279     } else {
00280         _initialized = false;
00281     }
00282 
00283     return _initialized;
00284 }
00285 
00286 // Note: Private helper function to initialize qspi HAL
00287 bool QSPI::_initialize_direct()
00288 {
00289     if (_mode != 0 && _mode != 1) {
00290         _initialized = false;
00291         return _initialized;
00292     }
00293 
00294     qspi_status_t ret = qspi_init_direct(&_qspi, _static_pinmap, _hz, _mode);
00295     if (QSPI_STATUS_OK == ret) {
00296         _initialized = true;
00297     } else {
00298         _initialized = false;
00299     }
00300 
00301     return _initialized;
00302 }
00303 
00304 // Note: Private function with no locking
00305 bool QSPI::_acquire()
00306 {
00307     if (_owner != this) {
00308         //This will set freq as well
00309         (this->*_init_func)();
00310         _owner = this;
00311     }
00312 
00313     return _initialized;
00314 }
00315 
00316 void QSPI::_build_qspi_command(qspi_inst_t instruction, int address, int alt)
00317 {
00318     memset(&_qspi_command, 0,  sizeof(qspi_command_t));
00319     //Set up instruction phase parameters
00320     _qspi_command.instruction.bus_width = _inst_width;
00321     if (instruction != QSPI_NO_INST) {
00322         _qspi_command.instruction.value = instruction;
00323         _qspi_command.instruction.disabled = false;
00324     } else {
00325         _qspi_command.instruction.disabled = true;
00326     }
00327 
00328     //Set up address phase parameters
00329     _qspi_command.address.bus_width = _address_width;
00330     _qspi_command.address.size = _address_size;
00331     if (address != -1) {
00332         _qspi_command.address.value = address;
00333         _qspi_command.address.disabled = false;
00334     } else {
00335         _qspi_command.address.disabled = true;
00336     }
00337 
00338     //Set up alt phase parameters
00339     _qspi_command.alt.bus_width = _alt_width;
00340     _qspi_command.alt.size = _alt_size;
00341     if (alt != -1) {
00342         _qspi_command.alt.value = alt;
00343         _qspi_command.alt.disabled = false;
00344     } else {
00345         _qspi_command.alt.disabled = true;
00346     }
00347 
00348     _qspi_command.dummy_count = _num_dummy_cycles;
00349 
00350     //Set up bus width for data phase
00351     _qspi_command.data.bus_width = _data_width;
00352 }
00353 
00354 } // namespace mbed
00355 
00356 #endif