Merge branch 'master' of https://github.com/SuperHouse/esp-open-rtos into sntp
This commit is contained in:
commit
f4a5675854
5 changed files with 561 additions and 24 deletions
251
core/esp_spi.c
Normal file
251
core/esp_spi.c
Normal file
|
@ -0,0 +1,251 @@
|
||||||
|
/*
|
||||||
|
* ESP hardware SPI master driver
|
||||||
|
*
|
||||||
|
* Part of esp-open-rtos
|
||||||
|
* Copyright (c) Ruslan V. Uss, 2016
|
||||||
|
* BSD Licensed as described in the file LICENSE
|
||||||
|
*/
|
||||||
|
#include "esp/spi.h"
|
||||||
|
|
||||||
|
#include "esp/iomux.h"
|
||||||
|
#include "esp/gpio.h"
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#define _SPI0_SCK_GPIO 6
|
||||||
|
#define _SPI0_MISO_GPIO 7
|
||||||
|
#define _SPI0_MOSI_GPIO 8
|
||||||
|
#define _SPI0_HD_GPIO 9
|
||||||
|
#define _SPI0_WP_GPIO 10
|
||||||
|
#define _SPI0_CS0_GPIO 11
|
||||||
|
|
||||||
|
#define _SPI1_MISO_GPIO 12
|
||||||
|
#define _SPI1_MOSI_GPIO 13
|
||||||
|
#define _SPI1_SCK_GPIO 14
|
||||||
|
#define _SPI1_CS0_GPIO 15
|
||||||
|
|
||||||
|
#define _SPI0_FUNC 1
|
||||||
|
#define _SPI1_FUNC 2
|
||||||
|
|
||||||
|
#define _SPI_BUF_SIZE 64
|
||||||
|
|
||||||
|
static bool _minimal_pins[2] = {false, false};
|
||||||
|
|
||||||
|
inline static void _set_pin_function(uint8_t pin, uint32_t function)
|
||||||
|
{
|
||||||
|
iomux_set_function(gpio_to_iomux(pin), function);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool spi_init(uint8_t bus, spi_mode_t mode, uint32_t freq_divider, bool msb, spi_endianness_t endianness, bool minimal_pins)
|
||||||
|
{
|
||||||
|
switch (bus)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
_set_pin_function(_SPI0_MISO_GPIO, _SPI0_FUNC);
|
||||||
|
_set_pin_function(_SPI0_MOSI_GPIO, _SPI0_FUNC);
|
||||||
|
_set_pin_function(_SPI0_SCK_GPIO, _SPI0_FUNC);
|
||||||
|
if (!minimal_pins)
|
||||||
|
{
|
||||||
|
_set_pin_function(_SPI0_HD_GPIO, _SPI0_FUNC);
|
||||||
|
_set_pin_function(_SPI0_WP_GPIO, _SPI0_FUNC);
|
||||||
|
_set_pin_function(_SPI0_CS0_GPIO, _SPI0_FUNC);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
_set_pin_function(_SPI1_MISO_GPIO, _SPI1_FUNC);
|
||||||
|
_set_pin_function(_SPI1_MOSI_GPIO, _SPI1_FUNC);
|
||||||
|
_set_pin_function(_SPI1_SCK_GPIO, _SPI1_FUNC);
|
||||||
|
if (!minimal_pins)
|
||||||
|
_set_pin_function(_SPI1_CS0_GPIO, _SPI1_FUNC);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
_minimal_pins[bus] = minimal_pins;
|
||||||
|
SPI(bus).USER0 = SPI_USER0_MOSI | SPI_USER0_CLOCK_IN_EDGE | SPI_USER0_DUPLEX |
|
||||||
|
(minimal_pins ? 0 : (SPI_USER0_CS_HOLD | SPI_USER0_CS_SETUP));
|
||||||
|
|
||||||
|
spi_set_frequency_div(bus, freq_divider);
|
||||||
|
spi_set_mode(bus, mode);
|
||||||
|
spi_set_msb(bus, msb);
|
||||||
|
spi_set_endianness(bus, endianness);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void spi_get_settings(uint8_t bus, spi_settings_t *s)
|
||||||
|
{
|
||||||
|
s->mode = spi_get_mode(bus);
|
||||||
|
s->freq_divider = spi_get_frequency_div(bus);
|
||||||
|
s->msb = spi_get_msb(bus);
|
||||||
|
s->endianness = spi_get_endianness(bus);
|
||||||
|
s->minimal_pins = _minimal_pins[bus];
|
||||||
|
}
|
||||||
|
|
||||||
|
void spi_set_mode(uint8_t bus, spi_mode_t mode)
|
||||||
|
{
|
||||||
|
bool cpha = (uint8_t)mode & 1;
|
||||||
|
bool cpol = (uint8_t)mode & 2;
|
||||||
|
if (cpol)
|
||||||
|
cpha = !cpha; // CPHA must be inverted when CPOL = 1, I have no idea why
|
||||||
|
|
||||||
|
// CPHA
|
||||||
|
if (cpha)
|
||||||
|
SPI(bus).USER0 |= SPI_USER0_CLOCK_OUT_EDGE;
|
||||||
|
else
|
||||||
|
SPI(bus).USER0 &= ~SPI_USER0_CLOCK_OUT_EDGE;
|
||||||
|
|
||||||
|
// CPOL - see http://bbs.espressif.com/viewtopic.php?t=342#p5384
|
||||||
|
if (cpol)
|
||||||
|
SPI(bus).PIN |= SPI_PIN_IDLE_EDGE;
|
||||||
|
else
|
||||||
|
SPI(bus).PIN &= ~SPI_PIN_IDLE_EDGE;
|
||||||
|
}
|
||||||
|
|
||||||
|
spi_mode_t spi_get_mode(uint8_t bus)
|
||||||
|
{
|
||||||
|
uint8_t cpha = SPI(bus).USER0 & SPI_USER0_CLOCK_OUT_EDGE ? 1 : 0;
|
||||||
|
uint8_t cpol = SPI(bus).PIN & SPI_PIN_IDLE_EDGE ? 2 : 0;
|
||||||
|
|
||||||
|
return (spi_mode_t)(cpol | (cpol ? 1 - cpha : cpha)); // see spi_set_mode
|
||||||
|
}
|
||||||
|
|
||||||
|
void spi_set_msb(uint8_t bus, bool msb)
|
||||||
|
{
|
||||||
|
if (msb)
|
||||||
|
SPI(bus).CTRL0 &= ~(SPI_CTRL0_WR_BIT_ORDER | SPI_CTRL0_RD_BIT_ORDER);
|
||||||
|
else
|
||||||
|
SPI(bus).CTRL0 |= (SPI_CTRL0_WR_BIT_ORDER | SPI_CTRL0_RD_BIT_ORDER);
|
||||||
|
}
|
||||||
|
|
||||||
|
void spi_set_endianness(uint8_t bus, spi_endianness_t endianness)
|
||||||
|
{
|
||||||
|
if (endianness == SPI_BIG_ENDIAN)
|
||||||
|
SPI(bus).USER0 |= (SPI_USER0_WR_BYTE_ORDER | SPI_USER0_RD_BYTE_ORDER);
|
||||||
|
else
|
||||||
|
SPI(bus).USER0 &= ~(SPI_USER0_WR_BYTE_ORDER | SPI_USER0_RD_BYTE_ORDER);
|
||||||
|
}
|
||||||
|
|
||||||
|
void spi_set_frequency_div(uint8_t bus, uint32_t divider)
|
||||||
|
{
|
||||||
|
uint32_t predivider = (divider & 0xffff) - 1;
|
||||||
|
uint32_t count = (divider >> 16) - 1;
|
||||||
|
if (count || predivider)
|
||||||
|
{
|
||||||
|
IOMUX.CONF &= ~(bus == 0 ? IOMUX_CONF_SPI0_CLOCK_EQU_SYS_CLOCK : IOMUX_CONF_SPI1_CLOCK_EQU_SYS_CLOCK);
|
||||||
|
SPI(bus).CLOCK = VAL2FIELD_M(SPI_CLOCK_DIV_PRE, predivider) |
|
||||||
|
VAL2FIELD_M(SPI_CLOCK_COUNT_NUM, count) |
|
||||||
|
VAL2FIELD_M(SPI_CLOCK_COUNT_HIGH, count / 2) |
|
||||||
|
VAL2FIELD_M(SPI_CLOCK_COUNT_LOW, count);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
IOMUX.CONF |= bus == 0 ? IOMUX_CONF_SPI0_CLOCK_EQU_SYS_CLOCK : IOMUX_CONF_SPI1_CLOCK_EQU_SYS_CLOCK;
|
||||||
|
SPI(bus).CLOCK = SPI_CLOCK_EQU_SYS_CLOCK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline static void _set_size(uint8_t bus, uint8_t bytes)
|
||||||
|
{
|
||||||
|
uint32_t bits = ((uint32_t)bytes << 3) - 1;
|
||||||
|
SPI(bus).USER1 = SET_FIELD(SPI(bus).USER1, SPI_USER1_MISO_BITLEN, bits);
|
||||||
|
SPI(bus).USER1 = SET_FIELD(SPI(bus).USER1, SPI_USER1_MOSI_BITLEN, bits);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline static void _wait(uint8_t bus)
|
||||||
|
{
|
||||||
|
while (SPI(bus).CMD & SPI_CMD_USR)
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline static void _start(uint8_t bus)
|
||||||
|
{
|
||||||
|
SPI(bus).CMD |= SPI_CMD_USR;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline static uint32_t _swap_bytes(uint32_t value)
|
||||||
|
{
|
||||||
|
return (value << 24) | ((value << 8) & 0x00ff0000) | ((value >> 8) & 0x0000ff00) | (value >> 24);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline static uint32_t _swap_words(uint32_t value)
|
||||||
|
{
|
||||||
|
return (value << 16) | (value >> 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _spi_buf_prepare(uint8_t bus, size_t len, spi_endianness_t e, spi_word_size_t word_size)
|
||||||
|
{
|
||||||
|
if (e == SPI_LITTLE_ENDIAN || word_size == SPI_32BIT) return;
|
||||||
|
|
||||||
|
size_t count = word_size == SPI_16BIT ? (len + 1) / 2 : (len + 3) / 4;
|
||||||
|
uint32_t *data = (uint32_t *)&SPI(bus).W0;
|
||||||
|
for (size_t i = 0; i < count; i ++)
|
||||||
|
{
|
||||||
|
data[i] = word_size == SPI_16BIT
|
||||||
|
? _swap_words(data[i])
|
||||||
|
: _swap_bytes(data[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _spi_buf_transfer(uint8_t bus, const void *out_data, void *in_data,
|
||||||
|
size_t len, spi_endianness_t e, spi_word_size_t word_size)
|
||||||
|
{
|
||||||
|
_wait(bus);
|
||||||
|
size_t bytes = len * (uint8_t)word_size;
|
||||||
|
_set_size(bus, bytes);
|
||||||
|
memcpy((void *)&SPI(bus).W0, out_data, bytes);
|
||||||
|
_spi_buf_prepare(bus, len, e, word_size);
|
||||||
|
_start(bus);
|
||||||
|
_wait(bus);
|
||||||
|
if (in_data)
|
||||||
|
{
|
||||||
|
_spi_buf_prepare(bus, len, e, word_size);
|
||||||
|
memcpy(in_data, (void *)&SPI(bus).W0, bytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t spi_transfer_8(uint8_t bus, uint8_t data)
|
||||||
|
{
|
||||||
|
uint8_t res;
|
||||||
|
_spi_buf_transfer(bus, &data, &res, 1, spi_get_endianness(bus), SPI_8BIT);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t spi_transfer_16(uint8_t bus, uint16_t data)
|
||||||
|
{
|
||||||
|
uint16_t res;
|
||||||
|
_spi_buf_transfer(bus, &data, &res, 1, spi_get_endianness(bus), SPI_16BIT);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t spi_transfer_32(uint8_t bus, uint32_t data)
|
||||||
|
{
|
||||||
|
uint32_t res;
|
||||||
|
_spi_buf_transfer(bus, &data, &res, 1, spi_get_endianness(bus), SPI_32BIT);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t spi_transfer(uint8_t bus, const void *out_data, void *in_data, size_t len, spi_word_size_t word_size)
|
||||||
|
{
|
||||||
|
if (!out_data || !len) return 0;
|
||||||
|
|
||||||
|
spi_endianness_t e = spi_get_endianness(bus);
|
||||||
|
uint8_t buf_size = _SPI_BUF_SIZE / (uint8_t)word_size;
|
||||||
|
|
||||||
|
size_t blocks = len / buf_size;
|
||||||
|
for (size_t i = 0; i < blocks; i++)
|
||||||
|
{
|
||||||
|
size_t offset = i * _SPI_BUF_SIZE;
|
||||||
|
_spi_buf_transfer(bus, (const uint8_t *)out_data + offset,
|
||||||
|
in_data ? (uint8_t *)in_data + offset : NULL, buf_size, e, word_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t tail = len % buf_size;
|
||||||
|
if (tail)
|
||||||
|
{
|
||||||
|
_spi_buf_transfer(bus, (const uint8_t *)out_data + blocks * _SPI_BUF_SIZE,
|
||||||
|
in_data ? (uint8_t *)in_data + blocks * _SPI_BUF_SIZE : NULL, tail, e, word_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
return len;
|
||||||
|
}
|
|
@ -13,6 +13,10 @@
|
||||||
#include "esp/iomux.h"
|
#include "esp/iomux.h"
|
||||||
#include "esp/interrupts.h"
|
#include "esp/interrupts.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
GPIO_INPUT,
|
GPIO_INPUT,
|
||||||
GPIO_OUTPUT, /* "Standard" push-pull output */
|
GPIO_OUTPUT, /* "Standard" push-pull output */
|
||||||
|
@ -139,4 +143,8 @@ static inline gpio_inttype_t gpio_get_interrupt(const uint8_t gpio_num)
|
||||||
return (gpio_inttype_t)FIELD2VAL(GPIO_CONF_INTTYPE, GPIO.CONF[gpio_num]);
|
return (gpio_inttype_t)FIELD2VAL(GPIO_CONF_INTTYPE, GPIO.CONF[gpio_num]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
272
core/include/esp/spi.h
Normal file
272
core/include/esp/spi.h
Normal file
|
@ -0,0 +1,272 @@
|
||||||
|
/**
|
||||||
|
* \file Hardware SPI master driver
|
||||||
|
*
|
||||||
|
* Part of esp-open-rtos
|
||||||
|
*
|
||||||
|
* \copyright Ruslan V. Uss, 2016
|
||||||
|
* BSD Licensed as described in the file LICENSE
|
||||||
|
*/
|
||||||
|
#ifndef _ESP_SPI_H_
|
||||||
|
#define _ESP_SPI_H_
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "esp/spi_regs.h"
|
||||||
|
#include "esp/clocks.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Macro for use with spi_init and spi_set_frequency_div.
|
||||||
|
* SPI frequency = 80000000 / divider / count
|
||||||
|
* dvider must be in 1..8192 and count in 1..64
|
||||||
|
*/
|
||||||
|
#define SPI_GET_FREQ_DIV(divider, count) (((count) << 16) | ((divider) & 0xffff))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Predefinded SPI frequency dividers
|
||||||
|
*/
|
||||||
|
#define SPI_FREQ_DIV_125K SPI_GET_FREQ_DIV(64, 10) ///< 125kHz
|
||||||
|
#define SPI_FREQ_DIV_250K SPI_GET_FREQ_DIV(32, 10) ///< 250kHz
|
||||||
|
#define SPI_FREQ_DIV_500K SPI_GET_FREQ_DIV(16, 10) ///< 500kHz
|
||||||
|
#define SPI_FREQ_DIV_1M SPI_GET_FREQ_DIV(8, 10) ///< 1MHz
|
||||||
|
#define SPI_FREQ_DIV_2M SPI_GET_FREQ_DIV(4, 10) ///< 2MHz
|
||||||
|
#define SPI_FREQ_DIV_4M SPI_GET_FREQ_DIV(2, 10) ///< 4MHz
|
||||||
|
#define SPI_FREQ_DIV_8M SPI_GET_FREQ_DIV(5, 2) ///< 8MHz
|
||||||
|
#define SPI_FREQ_DIV_10M SPI_GET_FREQ_DIV(4, 2) ///< 10MHz
|
||||||
|
#define SPI_FREQ_DIV_20M SPI_GET_FREQ_DIV(2, 2) ///< 20MHz
|
||||||
|
#define SPI_FREQ_DIV_40M SPI_GET_FREQ_DIV(1, 2) ///< 40MHz
|
||||||
|
#define SPI_FREQ_DIV_80M SPI_GET_FREQ_DIV(1, 1) ///< 80MHz
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef enum _spi_mode_t {
|
||||||
|
SPI_MODE0 = 0, ///< CPOL = 0, CPHA = 0
|
||||||
|
SPI_MODE1, ///< CPOL = 0, CPHA = 1
|
||||||
|
SPI_MODE2, ///< CPOL = 1, CPHA = 0
|
||||||
|
SPI_MODE3 ///< CPOL = 1, CPHA = 1
|
||||||
|
} spi_mode_t;
|
||||||
|
|
||||||
|
typedef enum _spi_endianness_t {
|
||||||
|
SPI_LITTLE_ENDIAN = 0,
|
||||||
|
SPI_BIG_ENDIAN
|
||||||
|
} spi_endianness_t;
|
||||||
|
|
||||||
|
typedef enum _spi_word_size_t {
|
||||||
|
SPI_8BIT = 1, ///< 1 byte
|
||||||
|
SPI_16BIT = 2, ///< 2 bytes
|
||||||
|
SPI_32BIT = 4 ///< 4 bytes
|
||||||
|
} spi_word_size_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SPI bus settings
|
||||||
|
*/
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
spi_mode_t mode; ///< Bus mode
|
||||||
|
uint32_t freq_divider; ///< Bus frequency as a divider. See spi_init()
|
||||||
|
bool msb; ///< MSB first if true
|
||||||
|
spi_endianness_t endianness; ///< Bus byte order
|
||||||
|
bool minimal_pins; ///< Minimal set of pins if true. Spee spi_init()
|
||||||
|
} spi_settings_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Initalize SPI bus
|
||||||
|
* Initalize specified SPI bus and setup appropriate pins:
|
||||||
|
* Bus 0:
|
||||||
|
* - MISO = GPIO 7
|
||||||
|
* - MOSI = GPIO 8
|
||||||
|
* - SCK = GPIO 6
|
||||||
|
* - CS0 = GPIO 11 (if minimal_pins is false)
|
||||||
|
* - HD = GPIO 9 (if minimal_pins is false)
|
||||||
|
* - WP = GPIO 10 (if minimal_pins is false)
|
||||||
|
* Bus 1:
|
||||||
|
* - MISO = GPIO 12
|
||||||
|
* - MOSI = GPIO 13
|
||||||
|
* - SCK = GPIO 14
|
||||||
|
* - CS0 = GPIO 15 (if minimal_pins is false)
|
||||||
|
* Note that system flash memory is on the bus 0!
|
||||||
|
* \param bus Bus ID: 0 - system, 1 - user
|
||||||
|
* \param mode Bus mode
|
||||||
|
* \param freq_divider SPI bus frequency divider, use SPI_GET_FREQ_DIV() or predefined value
|
||||||
|
* \param msb Bit order, MSB first if true
|
||||||
|
* \param endianness Byte order
|
||||||
|
* \param minimal_pins If true use the minimal set of pins: MISO, MOSI and SCK.
|
||||||
|
* \return false when error
|
||||||
|
*/
|
||||||
|
bool spi_init(uint8_t bus, spi_mode_t mode, uint32_t freq_divider, bool msb, spi_endianness_t endianness, bool minimal_pins);
|
||||||
|
/**
|
||||||
|
* \brief Initalize SPI bus
|
||||||
|
* spi_init() wrapper.
|
||||||
|
* Example:
|
||||||
|
*
|
||||||
|
* const spi_settings_t my_settings = {
|
||||||
|
* .mode = SPI_MODE0,
|
||||||
|
* .freq_divider = SPI_FREQ_DIV_4M,
|
||||||
|
* .msb = true,
|
||||||
|
* .endianness = SPI_LITTLE_ENDIAN,
|
||||||
|
* .minimal_pins = true
|
||||||
|
* }
|
||||||
|
* ....
|
||||||
|
* spi_settings_t old;
|
||||||
|
* spi_get_settings(1, &old); // save current settings
|
||||||
|
* //spi_init(1, SPI_MODE0, SPI_FREQ_DIV_4M, true, SPI_LITTLE_ENDIAN, true); // use own settings
|
||||||
|
* // or
|
||||||
|
* spi_set_settings(1, &my_settings);
|
||||||
|
* // some work with spi here
|
||||||
|
* ....
|
||||||
|
* spi_set_settings(1, &old); // restore saved settings
|
||||||
|
*
|
||||||
|
* \param s Pointer to the settings structure
|
||||||
|
* \return false when error
|
||||||
|
*/
|
||||||
|
static inline bool spi_set_settings(uint8_t bus, const spi_settings_t *s)
|
||||||
|
{
|
||||||
|
return spi_init(bus, s->mode, s->freq_divider, s->msb, s->endianness, s->minimal_pins);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* \brief Get current settings of the SPI bus
|
||||||
|
* See spi_set_settings().
|
||||||
|
* \param bus Bus ID: 0 - system, 1 - user
|
||||||
|
* \param s Pointer to the structure that receives SPI bus settings
|
||||||
|
*/
|
||||||
|
void spi_get_settings(uint8_t bus, spi_settings_t *s);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Set SPI bus mode
|
||||||
|
* \param bus Bus ID: 0 - system, 1 - user
|
||||||
|
* \param mode Bus mode
|
||||||
|
*/
|
||||||
|
void spi_set_mode(uint8_t bus, spi_mode_t mode);
|
||||||
|
/**
|
||||||
|
* \brief Get mode of the SPI bus
|
||||||
|
* \param bus Bus ID: 0 - system, 1 - user
|
||||||
|
* \return Bus mode
|
||||||
|
*/
|
||||||
|
spi_mode_t spi_get_mode(uint8_t bus);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Set SPI bus frequency
|
||||||
|
* Examples:
|
||||||
|
*
|
||||||
|
* spi_set_frequency_div(1, SPI_FREQ_DIV_8M); // 8 MHz, predefined value
|
||||||
|
* ...
|
||||||
|
* spi_set_frequency_div(1, SPI_GET_FREQ_DIV(8, 10)); // divider = 8, count = 10,
|
||||||
|
* // frequency = 80000000 Hz / 8 / 10 = 1000000 Hz
|
||||||
|
*
|
||||||
|
* \param bus Bus ID: 0 - system, 1 - user
|
||||||
|
* \param divider Predivider of the system bus frequency (80MHz) in the 2 low
|
||||||
|
* bytes and period pulses count in the third byte. Please note that
|
||||||
|
* divider must be be in range 1..8192 and count in range 2..64. Use the
|
||||||
|
* macro SPI_GET_FREQ_DIV(divider, count) to get the correct parameter value.
|
||||||
|
*/
|
||||||
|
void spi_set_frequency_div(uint8_t bus, uint32_t divider);
|
||||||
|
/**
|
||||||
|
* \brief Get SPI bus frequency as a divider
|
||||||
|
* Example:
|
||||||
|
*
|
||||||
|
* uint32_t old_freq = spi_get_frequency_div(1);
|
||||||
|
* spi_set_frequency_div(1, SPI_FREQ_DIV_8M);
|
||||||
|
* ...
|
||||||
|
* spi_set_frequency_div(1, old_freq);
|
||||||
|
*
|
||||||
|
* \param bus Bus ID: 0 - system, 1 - user
|
||||||
|
* \return SPI frequency, as divider.
|
||||||
|
*/
|
||||||
|
inline uint32_t spi_get_frequency_div(uint8_t bus)
|
||||||
|
{
|
||||||
|
return (FIELD2VAL(SPI_CLOCK_DIV_PRE, SPI(bus).CLOCK) + 1) |
|
||||||
|
(FIELD2VAL(SPI_CLOCK_COUNT_NUM, SPI(bus).CLOCK) + 1);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* \brief Get SPI bus frequency in Hz
|
||||||
|
* \param bus Bus ID: 0 - system, 1 - user
|
||||||
|
* \return SPI frequency, Hz
|
||||||
|
*/
|
||||||
|
inline uint32_t spi_get_frequency_hz(uint8_t bus)
|
||||||
|
{
|
||||||
|
return APB_CLK_FREQ /
|
||||||
|
(FIELD2VAL(SPI_CLOCK_DIV_PRE, SPI(bus).CLOCK) + 1) /
|
||||||
|
(FIELD2VAL(SPI_CLOCK_COUNT_NUM, SPI(bus).CLOCK) + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Set SPI bus bit order
|
||||||
|
* \param bus Bus ID: 0 - system, 1 - user
|
||||||
|
* \param msb Bit order, MSB first if true
|
||||||
|
*/
|
||||||
|
void spi_set_msb(uint8_t bus, bool msb);
|
||||||
|
/**
|
||||||
|
* \brief Get SPI bus bit order
|
||||||
|
* \param bus Bus ID: 0 - system, 1 - user
|
||||||
|
* \return msb Bit order, MSB first if true
|
||||||
|
*/
|
||||||
|
inline bool spi_get_msb(uint8_t bus)
|
||||||
|
{
|
||||||
|
return !(SPI(bus).CTRL0 & (SPI_CTRL0_WR_BIT_ORDER | SPI_CTRL0_RD_BIT_ORDER));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Set SPI bus byte order
|
||||||
|
* \param bus Bus ID: 0 - system, 1 - user
|
||||||
|
* \param endianness Byte order
|
||||||
|
*/
|
||||||
|
void spi_set_endianness(uint8_t bus, spi_endianness_t endianness);
|
||||||
|
/**
|
||||||
|
* \brief Get SPI bus byte order
|
||||||
|
* \param bus Bus ID: 0 - system, 1 - user
|
||||||
|
* \return endianness Byte order
|
||||||
|
*/
|
||||||
|
inline spi_endianness_t spi_get_endianness(uint8_t bus)
|
||||||
|
{
|
||||||
|
return SPI(bus).USER0 & (SPI_USER0_WR_BYTE_ORDER | SPI_USER0_RD_BYTE_ORDER)
|
||||||
|
? SPI_BIG_ENDIAN
|
||||||
|
: SPI_LITTLE_ENDIAN;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Transfer 8 bits over SPI
|
||||||
|
* \param bus Bus ID: 0 - system, 1 - user
|
||||||
|
* \param data Byte to send
|
||||||
|
* \return Received byte
|
||||||
|
*/
|
||||||
|
uint8_t spi_transfer_8(uint8_t bus, uint8_t data);
|
||||||
|
/**
|
||||||
|
* \brief Transfer 16 bits over SPI
|
||||||
|
* \param bus Bus ID: 0 - system, 1 - user
|
||||||
|
* \param data Word to send
|
||||||
|
* \return Received word
|
||||||
|
*/
|
||||||
|
uint16_t spi_transfer_16(uint8_t bus, uint16_t data);
|
||||||
|
/**
|
||||||
|
* \brief Transfer 32 bits over SPI
|
||||||
|
* \param bus Bus ID: 0 - system, 1 - user
|
||||||
|
* \param data dword to send
|
||||||
|
* \return Received dword
|
||||||
|
*/
|
||||||
|
uint32_t spi_transfer_32(uint8_t bus, uint32_t data);
|
||||||
|
/**
|
||||||
|
* \brief Transfer buffer of words over SPI
|
||||||
|
* Please note that the buffer size is in words, not in bytes!
|
||||||
|
* Example:
|
||||||
|
*
|
||||||
|
* const uint16_t out_buf[] = { 0xa0b0, 0xa1b1, 0xa2b2, 0xa3b3 };
|
||||||
|
* uint16_t in_buf[sizeof(out_buf)];
|
||||||
|
* spi_init(1, SPI_MODE1, SPI_FREQ_DIV_4M, true, SPI_BIG_ENDIAN, true);
|
||||||
|
* spi_transfer(1, out_buf, in_buf, sizeof(out_buf), SPI_16BIT); // len = 4 words * 2 bytes = 8 bytes
|
||||||
|
*
|
||||||
|
* \param bus Bus ID: 0 - system, 1 - user
|
||||||
|
* \param out_data Data to send.
|
||||||
|
* \param in_data Receive buffer. If NULL, received data will be lost.
|
||||||
|
* \param len Buffer size in words
|
||||||
|
* \param word_size Size of the word
|
||||||
|
* \return Transmitted/received words count
|
||||||
|
*/
|
||||||
|
size_t spi_transfer(uint8_t bus, const void *out_data, void *in_data, size_t len, spi_word_size_t word_size);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* _ESP_SPI_H_ */
|
|
@ -152,6 +152,7 @@ _Static_assert(sizeof(struct SPI_REGS) == 0x100, "SPI_REGS is the wrong size");
|
||||||
#define SPI_USER0_CS_SETUP BIT(5)
|
#define SPI_USER0_CS_SETUP BIT(5)
|
||||||
#define SPI_USER0_CS_HOLD BIT(4)
|
#define SPI_USER0_CS_HOLD BIT(4)
|
||||||
#define SPI_USER0_FLASH_MODE BIT(2)
|
#define SPI_USER0_FLASH_MODE BIT(2)
|
||||||
|
#define SPI_USER0_DUPLEX BIT(0)
|
||||||
|
|
||||||
/* Details for USER1 register */
|
/* Details for USER1 register */
|
||||||
|
|
||||||
|
@ -173,6 +174,7 @@ _Static_assert(sizeof(struct SPI_REGS) == 0x100, "SPI_REGS is the wrong size");
|
||||||
|
|
||||||
/* Details for PIN register */
|
/* Details for PIN register */
|
||||||
|
|
||||||
|
#define SPI_PIN_IDLE_EDGE BIT(29) ///< CPOL
|
||||||
#define SPI_PIN_CS2_DISABLE BIT(2)
|
#define SPI_PIN_CS2_DISABLE BIT(2)
|
||||||
#define SPI_PIN_CS1_DISABLE BIT(1)
|
#define SPI_PIN_CS1_DISABLE BIT(1)
|
||||||
#define SPI_PIN_CS0_DISABLE BIT(0)
|
#define SPI_PIN_CS0_DISABLE BIT(0)
|
||||||
|
|
|
@ -10,30 +10,34 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
const char *server_root_cert = "-----BEGIN CERTIFICATE-----\r\n"
|
const char *server_root_cert = "-----BEGIN CERTIFICATE-----\r\n"
|
||||||
"MIIEWTCCA0GgAwIBAgIDAjpjMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT\r\n"
|
"MIIFNzCCBB+gAwIBAgISAfl7TPw6Mf/F6VCBc5eaHA7kMA0GCSqGSIb3DQEBCwUA\r\n"
|
||||||
"MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i\r\n"
|
"MEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQD\r\n"
|
||||||
"YWwgQ0EwHhcNMTIwODI3MjA0MDQwWhcNMjIwNTIwMjA0MDQwWjBEMQswCQYDVQQG\r\n"
|
"ExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMTAeFw0xNTEyMzAwNzQ0MDBaFw0x\r\n"
|
||||||
"EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEdMBsGA1UEAxMUR2VvVHJ1c3Qg\r\n"
|
"NjAzMjkwNzQ0MDBaMBwxGjAYBgNVBAMTEXd3dy5ob3dzbXlzc2wuY29tMIIBIjAN\r\n"
|
||||||
"U1NMIENBIC0gRzIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC5J/lP\r\n"
|
"BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArKF7WzSrDPinQhd9mVfoW5u46/TC\r\n"
|
||||||
"2Pa3FT+Pzc7WjRxr/X/aVCFOA9jK0HJSFbjJgltYeYT/JHJv8ml/vJbZmnrDPqnP\r\n"
|
"fbYKR3MEryetUSeQuwuXFj2xO6+a/JQ99UC3Eq+9s8uFdx1zFFS6qfW+HXBwGWVf\r\n"
|
||||||
"UCITDoYZ2+hJ74vm1kfy/XNFCK6PrF62+J589xD/kkNm7xzU7qFGiBGJSXl6Jc5L\r\n"
|
"ajKEyIcXUJZCRn7aWpTWZq6cuv4bZSv1QklGViQs8UCZifcN0A/mYrH7zHG2WDn2\r\n"
|
||||||
"avDXHHYaKTzJ5P0ehdzgMWUFRxasCgdLLnBeawanazpsrwUSxLIRJdY+lynwg2xX\r\n"
|
"fxNgA+nJBqbZPr1gP9hqGFCnX+dPR5WxtC9+Dv9Sx+wiOWVz/obVTCygdqqcpa5I\r\n"
|
||||||
"HNil78zs/dYS8T/bQLSuDxjTxa9Akl0HXk7+Yhc3iemLdCai7bgK52wVWzWQct3Y\r\n"
|
"3/U9REVgO2VfT+xMty6NZTMCjTJ+GXZuB/BrMe9+ZmgWk0grJyqdrCxOCyK6B4g+\r\n"
|
||||||
"TSHUQCNcj+6AMRaraFX0DjtU6QRN8MxOgV7pb1JpTr6mFm1C9VH/4AtWPJhPc48O\r\n"
|
"Fvs8WFRNTHdQnP3/NT5hPtreZ3nuY2YY7RbGFwUaBcvJwbbIqalpiQ1X7QIDAQAB\r\n"
|
||||||
"bxoj8cnI2d+87FLXAgMBAAGjggFUMIIBUDAfBgNVHSMEGDAWgBTAephojYn7qwVk\r\n"
|
"o4ICQzCCAj8wDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggr\r\n"
|
||||||
"DBF9qn1luMrMTjAdBgNVHQ4EFgQUEUrQcznVW2kIXLo9v2SaqIscVbwwEgYDVR0T\r\n"
|
"BgEFBQcDAjAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBQMAe087CSp3PjgqyIYyWTR\r\n"
|
||||||
"AQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAQYwOgYDVR0fBDMwMTAvoC2gK4Yp\r\n"
|
"a2aMnTAfBgNVHSMEGDAWgBSoSmpjBH3duubRObemRWXv86jsoTBwBggrBgEFBQcB\r\n"
|
||||||
"aHR0cDovL2NybC5nZW90cnVzdC5jb20vY3Jscy9ndGdsb2JhbC5jcmwwNAYIKwYB\r\n"
|
"AQRkMGIwLwYIKwYBBQUHMAGGI2h0dHA6Ly9vY3NwLmludC14MS5sZXRzZW5jcnlw\r\n"
|
||||||
"BQUHAQEEKDAmMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5nZW90cnVzdC5jb20w\r\n"
|
"dC5vcmcvMC8GCCsGAQUFBzAChiNodHRwOi8vY2VydC5pbnQteDEubGV0c2VuY3J5\r\n"
|
||||||
"TAYDVR0gBEUwQzBBBgpghkgBhvhFAQc2MDMwMQYIKwYBBQUHAgEWJWh0dHA6Ly93\r\n"
|
"cHQub3JnLzBNBgNVHREERjBEgg1ob3dzbXlzc2wuY29tgg1ob3dzbXl0bHMuY29t\r\n"
|
||||||
"d3cuZ2VvdHJ1c3QuY29tL3Jlc291cmNlcy9jcHMwKgYDVR0RBCMwIaQfMB0xGzAZ\r\n"
|
"ghF3d3cuaG93c215dGxzLmNvbYIRd3d3Lmhvd3NteXNzbC5jb20wgf4GA1UdIASB\r\n"
|
||||||
"BgNVBAMTElZlcmlTaWduTVBLSS0yLTI1NDANBgkqhkiG9w0BAQUFAAOCAQEAPOU9\r\n"
|
"9jCB8zAIBgZngQwBAgEwgeYGCysGAQQBgt8TAQEBMIHWMCYGCCsGAQUFBwIBFhpo\r\n"
|
||||||
"WhuiNyrjRs82lhg8e/GExVeGd0CdNfAS8HgY+yKk3phLeIHmTYbjkQ9C47ncoNb/\r\n"
|
"dHRwOi8vY3BzLmxldHNlbmNyeXB0Lm9yZzCBqwYIKwYBBQUHAgIwgZ4MgZtUaGlz\r\n"
|
||||||
"qfixeZeZ0cNsQqWSlOBdDDMYJckrlVPg5akMfUf+f1ExRF73Kh41opQy98nuwLbG\r\n"
|
"IENlcnRpZmljYXRlIG1heSBvbmx5IGJlIHJlbGllZCB1cG9uIGJ5IFJlbHlpbmcg\r\n"
|
||||||
"mqzemSFqI6A4ZO6jxIhzMjtQzr+t03UepvTp+UJrYLLdRf1dVwjOLVDmEjIWE4ry\r\n"
|
"UGFydGllcyBhbmQgb25seSBpbiBhY2NvcmRhbmNlIHdpdGggdGhlIENlcnRpZmlj\r\n"
|
||||||
"lKKbR6iGf9mY5ffldnRk2JG8hBYo2CVEMH6C2Kyx5MDkFWzbtiQnAioBEoW6MYhY\r\n"
|
"YXRlIFBvbGljeSBmb3VuZCBhdCBodHRwczovL2xldHNlbmNyeXB0Lm9yZy9yZXBv\r\n"
|
||||||
"R3TjuNJkpsMyWS4pS0XxW4lJLoKaxhgVRNAuZAEVaDj59vlmAwxVG52/AECu8Egn\r\n"
|
"c2l0b3J5LzANBgkqhkiG9w0BAQsFAAOCAQEALB2QrIrcxxFr81b6khy9LwVBpthL\r\n"
|
||||||
"TOCAXi25KhV6vGb4NQ==\r\n"
|
"2LSs0xWhA09gxHmPnVrqim3Wa9HFYRApSqtTQWSx58TO+MERXQ7eDX50k53oem+Q\r\n"
|
||||||
|
"gXn90HVDkR0jbV1CsAD5qL00kKOofAyGkUhFlO2hcRU0CIj7Z9HZB8xpYdZWLUSZ\r\n"
|
||||||
|
"BpgiXdf/YYRIwgx29GRQjhfl/H30fHyawY5SvquJuvAeEr7lxqAmEEg3a7J6ibHL\r\n"
|
||||||
|
"90zf5KMkXGyVsXqxLqrEXQKgTvpUMeP5iYAxE45R5GNmYS2jajyTi4XkWw4nEu4Q\r\n"
|
||||||
|
"dMTLuwxGz87KOwSSFOLU903hO3IIPvFIIMY6aVK2kAgQPNIqk9nFurTF9A==\r\n"
|
||||||
"-----END CERTIFICATE-----\r\n";
|
"-----END CERTIFICATE-----\r\n";
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue