Radomir Dopieralski | 8e7dfea | 2016-06-07 21:40:56 +0200 | [diff] [blame] | 1 | /* |
| 2 | * The MIT License (MIT) |
| 3 | * |
| 4 | * Copyright (c) 2015 David Ogilvy (MetalPhreak) |
| 5 | * Modified 2016 by Radomir Dopieralski |
| 6 | * |
| 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy |
| 8 | * of this software and associated documentation files (the "Software"), to deal |
| 9 | * in the Software without restriction, including without limitation the rights |
| 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
| 11 | * copies of the Software, and to permit persons to whom the Software is |
| 12 | * furnished to do so, subject to the following conditions: |
| 13 | * |
| 14 | * The above copyright notice and this permission notice shall be included in all |
| 15 | * copies or substantial portions of the Software. |
| 16 | * |
| 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
| 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
| 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
| 23 | * SOFTWARE. |
| 24 | */ |
| 25 | |
| 26 | #include "hspi.h" |
| 27 | |
| 28 | /* |
| 29 | Wrapper to setup HSPI/SPI GPIO pins and default SPI clock |
| 30 | spi_no - SPI (0) or HSPI (1) |
| 31 | Not used in Micropython. |
| 32 | */ |
| 33 | void spi_init(uint8_t spi_no) { |
| 34 | spi_init_gpio(spi_no, SPI_CLK_USE_DIV); |
| 35 | spi_clock(spi_no, SPI_CLK_PREDIV, SPI_CLK_CNTDIV); |
| 36 | spi_tx_byte_order(spi_no, SPI_BYTE_ORDER_HIGH_TO_LOW); |
| 37 | spi_rx_byte_order(spi_no, SPI_BYTE_ORDER_HIGH_TO_LOW); |
| 38 | |
| 39 | SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_CS_SETUP|SPI_CS_HOLD); |
| 40 | CLEAR_PERI_REG_MASK(SPI_USER(spi_no), SPI_FLASH_MODE); |
| 41 | } |
| 42 | |
| 43 | |
| 44 | /* |
| 45 | Configures SPI mode parameters for clock edge and clock polarity. |
| 46 | spi_no - SPI (0) or HSPI (1) |
| 47 | spi_cpha - (0) Data is valid on clock leading edge |
| 48 | (1) Data is valid on clock trailing edge |
| 49 | spi_cpol - (0) Clock is low when inactive |
| 50 | (1) Clock is high when inactive |
| 51 | For Micropython this version is different from original. |
| 52 | */ |
| 53 | void spi_mode(uint8_t spi_no, uint8_t spi_cpha, uint8_t spi_cpol) { |
| 54 | if (spi_cpol) { |
| 55 | SET_PERI_REG_MASK(SPI_PIN(HSPI), SPI_IDLE_EDGE); |
| 56 | } else { |
| 57 | CLEAR_PERI_REG_MASK(SPI_PIN(HSPI), SPI_IDLE_EDGE); |
| 58 | } |
| 59 | if (spi_cpha == spi_cpol) { |
| 60 | // Mode 3 - MOSI is set on falling edge of clock |
| 61 | // Mode 0 - MOSI is set on falling edge of clock |
| 62 | CLEAR_PERI_REG_MASK(SPI_USER(HSPI), SPI_CK_OUT_EDGE); |
| 63 | SET_PERI_REG_MASK(SPI_USER(HSPI), SPI_CK_I_EDGE); |
| 64 | } else { |
| 65 | // Mode 2 - MOSI is set on rising edge of clock |
| 66 | // Mode 1 - MOSI is set on rising edge of clock |
| 67 | SET_PERI_REG_MASK(SPI_USER(HSPI), SPI_CK_OUT_EDGE); |
| 68 | CLEAR_PERI_REG_MASK(SPI_USER(HSPI), SPI_CK_I_EDGE); |
| 69 | } |
| 70 | } |
| 71 | |
| 72 | |
| 73 | /* |
| 74 | Initialise the GPIO pins for use as SPI pins. |
| 75 | spi_no - SPI (0) or HSPI (1) |
| 76 | sysclk_as_spiclk - |
| 77 | SPI_CLK_80MHZ_NODIV (1) if using 80MHz for SPI clock. |
| 78 | SPI_CLK_USE_DIV (0) if using divider for lower speed. |
| 79 | */ |
| 80 | void spi_init_gpio(uint8_t spi_no, uint8_t sysclk_as_spiclk) { |
| 81 | uint32_t clock_div_flag = 0; |
| 82 | if (sysclk_as_spiclk) { |
| 83 | clock_div_flag = 0x0001; |
| 84 | } |
| 85 | if (spi_no == SPI) { |
| 86 | // Set bit 8 if 80MHz sysclock required |
| 87 | WRITE_PERI_REG(PERIPHS_IO_MUX, 0x005 | (clock_div_flag<<8)); |
| 88 | PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_CLK_U, 1); |
| 89 | PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_CMD_U, 1); |
| 90 | PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_DATA0_U, 1); |
| 91 | PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_DATA1_U, 1); |
| 92 | } else if (spi_no == HSPI) { |
| 93 | // Set bit 9 if 80MHz sysclock required |
| 94 | WRITE_PERI_REG(PERIPHS_IO_MUX, 0x105 | (clock_div_flag<<9)); |
| 95 | // GPIO12 is HSPI MISO pin (Master Data In) |
| 96 | PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDI_U, 2); |
| 97 | // GPIO13 is HSPI MOSI pin (Master Data Out) |
| 98 | PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTCK_U, 2); |
| 99 | // GPIO14 is HSPI CLK pin (Clock) |
| 100 | PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTMS_U, 2); |
| 101 | // GPIO15 is HSPI CS pin (Chip Select / Slave Select) |
| 102 | // In Micropython, we are handling CS ourself in drivers. |
| 103 | // PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDO_U, 2); |
| 104 | } |
| 105 | } |
| 106 | |
| 107 | |
| 108 | /* |
| 109 | Set up the control registers for the SPI clock |
| 110 | spi_no - SPI (0) or HSPI (1) |
| 111 | prediv - predivider value (actual division value) |
| 112 | cntdiv - postdivider value (actual division value) |
| 113 | Set either divider to 0 to disable all division (80MHz sysclock) |
| 114 | */ |
| 115 | void spi_clock(uint8_t spi_no, uint16_t prediv, uint8_t cntdiv) { |
| 116 | if (prediv == 0 || cntdiv == 0) { |
| 117 | WRITE_PERI_REG(SPI_CLOCK(spi_no), SPI_CLK_EQU_SYSCLK); |
| 118 | } else { |
| 119 | WRITE_PERI_REG(SPI_CLOCK(spi_no), |
| 120 | (((prediv - 1) & SPI_CLKDIV_PRE) << SPI_CLKDIV_PRE_S) | |
| 121 | (((cntdiv - 1) & SPI_CLKCNT_N) << SPI_CLKCNT_N_S) | |
| 122 | (((cntdiv >> 1) & SPI_CLKCNT_H) << SPI_CLKCNT_H_S) | |
| 123 | ((0 & SPI_CLKCNT_L) << SPI_CLKCNT_L_S) |
| 124 | ); |
| 125 | } |
| 126 | } |
| 127 | |
| 128 | |
| 129 | /* |
| 130 | Setup the byte order for shifting data out of buffer |
| 131 | spi_no - SPI (0) or HSPI (1) |
| 132 | byte_order - |
| 133 | SPI_BYTE_ORDER_HIGH_TO_LOW (1) |
| 134 | Data is sent out starting with Bit31 and down to Bit0 |
| 135 | SPI_BYTE_ORDER_LOW_TO_HIGH (0) |
| 136 | Data is sent out starting with the lowest BYTE, from MSB to LSB, |
| 137 | followed by the second lowest BYTE, from MSB to LSB, followed by |
| 138 | the second highest BYTE, from MSB to LSB, followed by the highest |
| 139 | BYTE, from MSB to LSB 0xABCDEFGH would be sent as 0xGHEFCDAB. |
| 140 | */ |
| 141 | void spi_tx_byte_order(uint8_t spi_no, uint8_t byte_order) { |
| 142 | if (byte_order) { |
| 143 | SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_WR_BYTE_ORDER); |
| 144 | } else { |
| 145 | CLEAR_PERI_REG_MASK(SPI_USER(spi_no), SPI_WR_BYTE_ORDER); |
| 146 | } |
| 147 | } |
| 148 | |
| 149 | |
| 150 | /* |
| 151 | Setup the byte order for shifting data into buffer |
| 152 | spi_no - SPI (0) or HSPI (1) |
| 153 | byte_order - |
| 154 | SPI_BYTE_ORDER_HIGH_TO_LOW (1) |
| 155 | Data is read in starting with Bit31 and down to Bit0 |
| 156 | SPI_BYTE_ORDER_LOW_TO_HIGH (0) |
| 157 | Data is read in starting with the lowest BYTE, from MSB to LSB, |
| 158 | followed by the second lowest BYTE, from MSB to LSB, followed by |
| 159 | the second highest BYTE, from MSB to LSB, followed by the highest |
| 160 | BYTE, from MSB to LSB 0xABCDEFGH would be read as 0xGHEFCDAB |
| 161 | */ |
| 162 | void spi_rx_byte_order(uint8_t spi_no, uint8_t byte_order) { |
| 163 | if (byte_order) { |
| 164 | SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_RD_BYTE_ORDER); |
| 165 | } else { |
| 166 | CLEAR_PERI_REG_MASK(SPI_USER(spi_no), SPI_RD_BYTE_ORDER); |
| 167 | } |
| 168 | } |
| 169 | |
| 170 | |
| 171 | /* |
| 172 | SPI transaction function |
| 173 | spi_no - SPI (0) or HSPI (1) |
| 174 | cmd_bits - actual number of bits to transmit |
| 175 | cmd_data - command data |
| 176 | addr_bits - actual number of bits to transmit |
| 177 | addr_data - address data |
| 178 | dout_bits - actual number of bits to transmit |
| 179 | dout_data - output data |
| 180 | din_bits - actual number of bits to receive |
| 181 | Returns: read data - uint32_t containing read in data only if RX was set |
| 182 | 0 - something went wrong (or actual read data was 0) |
| 183 | 1 - data sent ok (or actual read data is 1) |
| 184 | Note: all data is assumed to be stored in the lower bits of the data variables |
| 185 | (for anything <32 bits). |
| 186 | */ |
| 187 | uint32_t spi_transaction(uint8_t spi_no, uint8_t cmd_bits, uint16_t cmd_data, |
| 188 | uint32_t addr_bits, uint32_t addr_data, |
| 189 | uint32_t dout_bits, uint32_t dout_data, |
| 190 | uint32_t din_bits, uint32_t dummy_bits) { |
| 191 | while (spi_busy(spi_no)) {}; // Wait for SPI to be ready |
| 192 | |
| 193 | // Enable SPI Functions |
| 194 | // Disable MOSI, MISO, ADDR, COMMAND, DUMMY in case previously set. |
| 195 | CLEAR_PERI_REG_MASK(SPI_USER(spi_no), SPI_USR_MOSI | SPI_USR_MISO | |
| 196 | SPI_USR_COMMAND | SPI_USR_ADDR | SPI_USR_DUMMY); |
| 197 | |
| 198 | // Enable functions based on number of bits. 0 bits = disabled. |
| 199 | // This is rather inefficient but allows for a very generic function. |
| 200 | // CMD ADDR and MOSI are set below to save on an extra if statement. |
| 201 | if (din_bits) { |
Radomir Dopieralski | 891479e | 2016-08-25 10:42:33 +0200 | [diff] [blame] | 202 | if (dout_bits) { |
| 203 | SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_DOUTDIN); |
| 204 | } else { |
| 205 | SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_USR_MISO); |
| 206 | } |
Radomir Dopieralski | 8e7dfea | 2016-06-07 21:40:56 +0200 | [diff] [blame] | 207 | } |
| 208 | if (dummy_bits) { |
| 209 | SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_USR_DUMMY); |
| 210 | } |
| 211 | |
| 212 | // Setup Bitlengths |
| 213 | WRITE_PERI_REG(SPI_USER1(spi_no), |
| 214 | // Number of bits in Address |
| 215 | ((addr_bits - 1) & SPI_USR_ADDR_BITLEN) << SPI_USR_ADDR_BITLEN_S | |
| 216 | // Number of bits to Send |
| 217 | ((dout_bits - 1) & SPI_USR_MOSI_BITLEN) << SPI_USR_MOSI_BITLEN_S | |
| 218 | // Number of bits to receive |
| 219 | ((din_bits - 1) & SPI_USR_MISO_BITLEN) << SPI_USR_MISO_BITLEN_S | |
| 220 | // Number of Dummy bits to insert |
| 221 | ((dummy_bits - 1) & SPI_USR_DUMMY_CYCLELEN) << SPI_USR_DUMMY_CYCLELEN_S); |
| 222 | |
| 223 | // Setup Command Data |
| 224 | if (cmd_bits) { |
| 225 | // Enable COMMAND function in SPI module |
| 226 | SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_USR_COMMAND); |
| 227 | // Align command data to high bits |
| 228 | uint16_t command = cmd_data << (16-cmd_bits); |
| 229 | // Swap byte order |
| 230 | command = ((command>>8)&0xff) | ((command<<8)&0xff00); |
| 231 | WRITE_PERI_REG(SPI_USER2(spi_no), ( |
| 232 | (((cmd_bits - 1) & SPI_USR_COMMAND_BITLEN) << SPI_USR_COMMAND_BITLEN_S) | |
| 233 | (command & SPI_USR_COMMAND_VALUE) |
| 234 | )); |
| 235 | } |
| 236 | |
| 237 | // Setup Address Data |
| 238 | if (addr_bits) { |
| 239 | // Enable ADDRess function in SPI module |
| 240 | SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_USR_ADDR); |
| 241 | // Align address data to high bits |
| 242 | WRITE_PERI_REG(SPI_ADDR(spi_no), addr_data << (32 - addr_bits)); |
| 243 | } |
| 244 | |
| 245 | // Setup DOUT data |
| 246 | if (dout_bits) { |
| 247 | // Enable MOSI function in SPI module |
| 248 | SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_USR_MOSI); |
| 249 | // Copy data to W0 |
| 250 | if (READ_PERI_REG(SPI_USER(spi_no))&SPI_WR_BYTE_ORDER) { |
| 251 | WRITE_PERI_REG(SPI_W0(spi_no), dout_data << (32 - dout_bits)); |
| 252 | } else { |
| 253 | uint8_t dout_extra_bits = dout_bits%8; |
| 254 | |
| 255 | if (dout_extra_bits) { |
| 256 | // If your data isn't a byte multiple (8/16/24/32 bits) and you |
| 257 | // don't have SPI_WR_BYTE_ORDER set, you need this to move the |
| 258 | // non-8bit remainder to the MSBs. Not sure if there's even a use |
| 259 | // case for this, but it's here if you need it... For example, |
| 260 | // 0xDA4 12 bits without SPI_WR_BYTE_ORDER would usually be output |
| 261 | // as if it were 0x0DA4, of which 0xA4, and then 0x0 would be |
| 262 | // shifted out (first 8 bits of low byte, then 4 MSB bits of high |
| 263 | // byte - ie reverse byte order). |
| 264 | // The code below shifts it out as 0xA4 followed by 0xD as you |
| 265 | // might require. |
| 266 | WRITE_PERI_REG(SPI_W0(spi_no), ( |
| 267 | (0xFFFFFFFF << (dout_bits - dout_extra_bits) & dout_data) |
| 268 | << (8-dout_extra_bits) | |
| 269 | ((0xFFFFFFFF >> (32 - (dout_bits - dout_extra_bits))) |
| 270 | & dout_data) |
| 271 | )); |
| 272 | } else { |
| 273 | WRITE_PERI_REG(SPI_W0(spi_no), dout_data); |
| 274 | } |
| 275 | } |
| 276 | } |
| 277 | |
| 278 | // Begin SPI Transaction |
| 279 | SET_PERI_REG_MASK(SPI_CMD(spi_no), SPI_USR); |
| 280 | |
| 281 | // Return DIN data |
| 282 | if (din_bits) { |
| 283 | while (spi_busy(spi_no)) {}; // Wait for SPI transaction to complete |
| 284 | if (READ_PERI_REG(SPI_USER(spi_no))&SPI_RD_BYTE_ORDER) { |
| 285 | // Assuming data in is written to MSB. TBC |
| 286 | return READ_PERI_REG(SPI_W0(spi_no)) >> (32 - din_bits); |
| 287 | } else { |
| 288 | // Read in the same way as DOUT is sent. Note existing contents of |
| 289 | // SPI_W0 remain unless overwritten! |
| 290 | return READ_PERI_REG(SPI_W0(spi_no)); |
| 291 | } |
| 292 | return 0; // Something went wrong |
| 293 | } |
| 294 | |
| 295 | // Transaction completed |
| 296 | return 1; // Success |
| 297 | } |
| 298 | |
| 299 | |
| 300 | /* |
| 301 | Just do minimal work needed to send 8 bits. |
| 302 | */ |
| 303 | inline void spi_tx8fast(uint8_t spi_no, uint8_t dout_data) { |
| 304 | while (spi_busy(spi_no)) {}; // Wait for SPI to be ready |
| 305 | |
| 306 | // Enable SPI Functions |
| 307 | // Disable MOSI, MISO, ADDR, COMMAND, DUMMY in case previously set. |
| 308 | CLEAR_PERI_REG_MASK(SPI_USER(spi_no), SPI_USR_MOSI | SPI_USR_MISO | |
| 309 | SPI_USR_COMMAND | SPI_USR_ADDR | SPI_USR_DUMMY); |
| 310 | |
| 311 | // Setup Bitlengths |
| 312 | WRITE_PERI_REG(SPI_USER1(spi_no), |
| 313 | // Number of bits to Send |
| 314 | ((8 - 1) & SPI_USR_MOSI_BITLEN) << SPI_USR_MOSI_BITLEN_S | |
| 315 | // Number of bits to receive |
| 316 | ((8 - 1) & SPI_USR_MISO_BITLEN) << SPI_USR_MISO_BITLEN_S); |
| 317 | |
| 318 | |
| 319 | // Setup DOUT data |
| 320 | // Enable MOSI function in SPI module |
| 321 | SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_USR_MOSI); |
| 322 | // Copy data to W0 |
| 323 | if (READ_PERI_REG(SPI_USER(spi_no)) & SPI_WR_BYTE_ORDER) { |
| 324 | WRITE_PERI_REG(SPI_W0(spi_no), dout_data << (32 - 8)); |
| 325 | } else { |
| 326 | WRITE_PERI_REG(SPI_W0(spi_no), dout_data); |
| 327 | } |
| 328 | |
| 329 | // Begin SPI Transaction |
| 330 | SET_PERI_REG_MASK(SPI_CMD(spi_no), SPI_USR); |
| 331 | } |