esp-idf/examples/09_a2dp/components/MediaHal/Driver/spi.c
wangmengyang 0ad3017df7 component/bt: A2DP code original in example project moved to component/bt directory;
1. move btif and A2DP source code from project directory to bluetooth directory;
2. some updates of audio source code;
2016-12-26 17:40:28 +08:00

828 lines
27 KiB
C

// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
//
// 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 <string.h>
#include "spi.h"
#include "soc/spi_reg.h"
#include "soc/rtc_cntl_reg.h"
#include "rom/ets_sys.h"
#include "esp_intr.h"
#include "soc/dport_reg.h"
//*****************************************************************************
//
// Make sure all of the definitions in this header have a C binding.
//
//*****************************************************************************
#ifdef __cplusplus
extern "C"
{
#endif
/**
* @brief Defines slave commands.Default value based on slave ESP8266 & ESP32.
*/
#define MASTER_WRITE_DATA_TO_SLAVE_CMD 2
#define MASTER_READ_DATA_FROM_SLAVE_CMD 3
#define MASTER_WRITE_STATUS_TO_SLAVE_CMD 1
#define MASTER_READ_STATUS_FROM_SLAVE_CMD 4
static void spi_intr_func_set(void * isr, spi_num_t spiNum)
{
if (SPI_NUM_SPI1 == spiNum) {
intr_matrix_set(0, ETS_SPI1_DMA_INTR_SOURCE, ETS_SPI1_INUM);
ESP_SPI1_INTR_ATTACH(isr, NULL);
// enable intr in cpu
ESP_SPI1_INTR_ENABLE();
} else if (SPI_NUM_SPI2 == spiNum) {
intr_matrix_set(0, ETS_SPI2_DMA_INTR_SOURCE, ETS_SPI2_INUM);
ESP_SPI2_INTR_ATTACH(isr, NULL);
// enable intr in cpu
ESP_SPI2_INTR_ENABLE();
} else if (SPI_NUM_SPI3 == spiNum) {
intr_matrix_set(0, ETS_SPI3_DMA_INTR_SOURCE, ETS_SPI3_INUM);
ESP_SPI3_INTR_ATTACH(isr, NULL);
// enable intr in cpu
ESP_SPI3_INTR_ENABLE();
} else {
// To do nothing
}
}
#if 1
/**
* @brief Get SPI ping buffer address.
*
*/
uint32_t* spi_dma_ping_buf_get(spi_dma_attr_t *obj)
{
if (NULL == obj) {
return NULL;
}
return obj->buf->ping->buffer_addr;
}
/**
* @brief Get SPI ping buffer address.
*
*/
uint32_t* spi_dma_pong_buf_get(spi_dma_attr_t *obj)
{
if (NULL == obj) {
return NULL;
}
return obj->buf->pong->buffer_addr;
}
/**
* @brief Get without work ping-pong buffer address.
*
*/
uint32_t* spi_dma_status_get(spi_dma_attr_t *obj)
{
if ((NULL == obj)
|| (obj->spi_num > SPI_NUM_MAX)) {
return NULL;
}
switch (obj->dir) {
case SPI_DMA_DIR_OUT:
if (READ_PERI_REG(SPI_OUT_EOF_DES_ADDR_REG(obj->spi_num)) == ((uint32_t)obj->buf->ping->last_queue)) {
return obj->buf->ping->buffer_addr;
} else if (READ_PERI_REG(SPI_OUT_EOF_DES_ADDR_REG(obj->spi_num)) == ((uint32_t)obj->buf->pong->last_queue)) {
return obj->buf->pong->buffer_addr;
}
break;
case SPI_DMA_DIR_IN:
if (READ_PERI_REG(SPI_IN_SUC_EOF_DES_ADDR_REG(obj->spi_num)) == ((uint32_t)obj->buf->ping->last_queue)) {
return obj->buf->ping->buffer_addr;
} else if (READ_PERI_REG(SPI_IN_SUC_EOF_DES_ADDR_REG(obj->spi_num)) == ((uint32_t)obj->buf->pong->last_queue)) {
return obj->buf->pong->buffer_addr;
}
break;
default:
break;
}
return NULL;
}
/**
* @brief Configrate the Ping-Pong buffer to the destination
*
*/
void spi_dma_dest_add_set(spi_dma_attr_t *obj)
{
if ((NULL == obj)
|| (obj->spi_num > SPI_NUM_MAX)) {
return;
}
if (SPI_DMA_DIR_IN == obj->dir) {
SET_PERI_REG_BITS(SPI_DMA_IN_LINK_REG(obj->spi_num), SPI_INLINK_ADDR, ((uint32_t)(obj->buf->ping->first_queue)), SPI_INLINK_ADDR_S);
} else if (SPI_DMA_DIR_OUT == obj->dir) {
SET_PERI_REG_BITS(SPI_DMA_OUT_LINK_REG(obj->spi_num), SPI_OUTLINK_ADDR, ((uint32_t)(obj->buf->ping->first_queue)), SPI_OUTLINK_ADDR_S);
}
}
/**
* @brief Reset SPI ping buffer address.
*
*/
void spi_dma_rest(spi_dma_attr_t *obj)
{
if ((NULL == obj)
|| (obj->spi_num > SPI_NUM_MAX)) {
return;
}
dma_buf_len_reset(obj->buf);
}
/**
* @brief Initialize DMA and create a SPI DMA instance.
*
*/
int spi_dma_init(spi_dma_attr_t *obj, void *isr)
{
if ((NULL == obj)
|| (obj->spi_num > SPI_NUM_MAX)) {
return -1;
}
obj->buf = dma_buf_create(obj->buf_size);
if (NULL == obj->buf) {
return -2;
}
// Reset DMA
SET_PERI_REG_MASK(SPI_DMA_CONF_REG(obj->spi_num), SPI_OUT_RST | SPI_AHBM_RST | SPI_AHBM_FIFO_RST);
CLEAR_PERI_REG_MASK(SPI_DMA_OUT_LINK_REG(obj->spi_num), SPI_OUTLINK_START);
CLEAR_PERI_REG_MASK(SPI_DMA_IN_LINK_REG(obj->spi_num), SPI_INLINK_START);
CLEAR_PERI_REG_MASK(SPI_DMA_CONF_REG(obj->spi_num), SPI_OUT_RST | SPI_AHBM_RST | SPI_AHBM_FIFO_RST);
// Select DMA channel.
SET_PERI_REG_BITS(DPORT_SPI_DMA_CHAN_SEL_REG, 3, obj->channel, ((obj->spi_num - 1) * 2));
SET_PERI_REG_MASK(SPI_USER_REG(obj->spi_num), SPI_USR_MOSI);//////add
if ((SPI_MODE_MASTER == obj->mode)) {
// enable send intr
SET_PERI_REG_MASK(SPI_DMA_INT_ENA_REG(obj->spi_num ), SPI_INT_SRC_ONE_BUF_SEND_DONE);
SET_PERI_REG_MASK(SPI_DMA_INT_ENA_REG(obj->spi_num ), SPI_INT_SRC_ONE_BUF_RECV_DONE);
} else if ((SPI_MODE_SLAVE == obj->mode)) {
SET_PERI_REG_MASK(SPI_SLV_RDBUF_DLEN_REG(obj->spi_num), ((obj->buf_size << 3) - 1));
SET_PERI_REG_MASK(SPI_SLV_WRBUF_DLEN_REG(obj->spi_num), ((obj->buf_size << 3) - 1));
// enable receive intr
SET_PERI_REG_MASK(SPI_DMA_INT_ENA_REG(obj->spi_num), SPI_INT_SRC_ONE_BUF_RECV_DONE);
}
// Clear all of interrupt source
spi_int_clear(obj->spi_num);
spi_intr_func_set(isr, obj->spi_num);
return 0;
}
/**
* @brief Destroy the SPI DMA instance
*
*/
int spi_dma_uninit(spi_dma_attr_t *obj)
{
if (NULL == obj) {
return -1;
}
dma_buf_destroy(obj->buf);
return 0;
}
/**
* @brief Enable the SPI DMA work mode.
*
*/
static void spi_dma_enable(spi_dma_attr_t *obj)
{
if ((NULL == obj)
|| (obj->spi_num > SPI_NUM_MAX)) {
return;
}
if (SPI_DMA_DIR_IN == obj->dir) {
WRITE_PERI_REG(0x3ff000c4,1<<22);
WRITE_PERI_REG(0x3ff000c4,0);
SET_PERI_REG_MASK(SPI_DMA_OUT_LINK_REG(obj->spi_num), SPI_OUTLINK_START);
SET_PERI_REG_MASK(SPI_DMA_IN_LINK_REG(obj->spi_num), SPI_INLINK_START);
// LOGD("recv-01:length=%x",READ_PERI_REG(SPI_DMA_TSTATUS_REG(obj->spi_num))>>18);
// while (((READ_PERI_REG(SPI_DMA_TSTATUS_REG(obj->spi_num))>>18)&0x3)!=0x3){
//LOGD("recv-01:length=%x",READ_PERI_REG(SPI_DMA_TSTATUS_REG(obj->spi_num))>>18);
// }
} else if (SPI_DMA_DIR_OUT == obj->dir) {
SET_PERI_REG_MASK(SPI_DMA_IN_LINK_REG(obj->spi_num), SPI_INLINK_START);
SET_PERI_REG_MASK(SPI_DMA_OUT_LINK_REG(obj->spi_num), SPI_OUTLINK_START);
// Waiting DMA controller fill TX FIFO
while ((READ_PERI_REG(SPI_DMA_RSTATUS_REG(obj->spi_num))&0x80000000));
}
}
/**
* @brief Disable the SPI DMA work mode.
*
*/
static void spi_dma_disable(spi_dma_attr_t *obj)
{
if ((NULL == obj)
|| (obj->spi_num > SPI_NUM_MAX)) {
return;
}
if (SPI_DMA_DIR_IN == obj->dir) {
CLEAR_PERI_REG_MASK(SPI_DMA_IN_LINK_REG(obj->spi_num), SPI_INLINK_STOP);
} else if (SPI_DMA_DIR_OUT == obj->dir) {
CLEAR_PERI_REG_MASK(SPI_DMA_OUT_LINK_REG(obj->spi_num), SPI_OUTLINK_STOP);
}
}
/**
* @brief Enable SPI DMA interrupt source.
*
*/
void spi_dma_int_enable(spi_num_t spiNum, spi_int_src_t intSrc)
{
if (spiNum > SPI_NUM_MAX) {
return;
}
SET_PERI_REG_MASK(SPI_DMA_INT_ENA_REG(spiNum), intSrc);
}
/**
* @brief Disable SPI DMA interrupt source.
*
*/
void spi_dma_int_disable(spi_num_t spiNum, spi_int_src_t intSrc)
{
if (spiNum > SPI_NUM_MAX) {
return;
}
SET_PERI_REG_MASK(SPI_DMA_INT_ENA_REG(spiNum), intSrc);
}
/**
* @brief Clear all of SPI DMA interrupt source.
*
*/
void spi_dma_int_clear(spi_num_t spiNum)
{
if (spiNum > SPI_NUM_MAX) {
return;
}
SET_PERI_REG_MASK(SPI_DMA_INT_CLR_REG(spiNum), 0x1FF);
}
/**
* @brief Get the SPI DMA interrupt status.
*
*/
int32_t spi_dma_int_status_get(spi_num_t spiNum)
{
if (spiNum > SPI_NUM_MAX) {
return -1;
}
return READ_PERI_REG(SPI_DMA_INT_ST_REG(spiNum));
}
/**
* @brief Start SPI work by DMA
*
*/
void spi_dma_start(spi_dma_attr_t *obj, uint32_t len)
{
if ((NULL == obj)
|| (obj->spi_num > SPI_NUM_MAX)) {
return;
}
// Reset DMA controller
SET_PERI_REG_MASK(SPI_DMA_CONF_REG(obj->spi_num), SPI_OUT_RST | SPI_IN_RST | SPI_AHBM_RST | SPI_AHBM_FIFO_RST);
CLEAR_PERI_REG_MASK(SPI_DMA_CONF_REG(obj->spi_num), SPI_OUT_RST | SPI_IN_RST | SPI_AHBM_RST | SPI_AHBM_FIFO_RST);
if (SPI_MODE_MASTER == obj->mode) {
CLEAR_PERI_REG_MASK(SPI_DMA_CONF_REG(obj->spi_num), SPI_DMA_CONTINUE);
if (obj->dir == SPI_DMA_DIR_IN) {
SET_PERI_REG_BITS(SPI_MISO_DLEN_REG(obj->spi_num), SPI_USR_MISO_DBITLEN, ((len << 3) - 1), SPI_USR_MISO_DBITLEN_S);
SET_PERI_REG_BITS(SPI_MOSI_DLEN_REG(obj->spi_num), SPI_USR_MOSI_DBITLEN, ((len << 3) - 1), SPI_USR_MOSI_DBITLEN_S);
}else{
SET_PERI_REG_BITS(SPI_MISO_DLEN_REG(obj->spi_num), SPI_USR_MISO_DBITLEN, ((len << 3) - 1), SPI_USR_MISO_DBITLEN_S);
SET_PERI_REG_BITS(SPI_MOSI_DLEN_REG(obj->spi_num), SPI_USR_MOSI_DBITLEN, ((len << 3) - 1), SPI_USR_MOSI_DBITLEN_S);
}
} else if (SPI_MODE_SLAVE == obj->mode) {
if (0 == len) {
SET_PERI_REG_MASK(SPI_DMA_CONF_REG(obj->spi_num), SPI_DMA_CONTINUE);
} else {
CLEAR_PERI_REG_MASK(SPI_DMA_CONF_REG(obj->spi_num), SPI_DMA_CONTINUE);
}
}
// 1.Enable DMA
spi_dma_enable(obj);
//LOGD("recv start before:%08x\n",obj->buf->ping->first_queue->data_length);
// LOGD("SPI_DMA_STATUS_REG=%x",READ_PERI_REG(SPI_DMA_STATUS_REG(obj->spi_num)));
// 2.Start SPI
SET_PERI_REG_MASK(SPI_CMD_REG(obj->spi_num), SPI_USR);
//LOGD("recv start after:%08x\n",obj->buf->ping->first_queue->data_length);
}
/**
* @brief Stop SPI work by DMA
*
*/
void spi_dma_stop(spi_dma_attr_t *obj)
{
if ((NULL == obj)
|| (obj->spi_num > SPI_NUM_MAX)) {
return;
}
if (SPI_MODE_MASTER == obj->mode) {
SET_PERI_REG_MASK(SPI_DMA_CONF_REG(obj->spi_num), SPI_DMA_TX_STOP);
} else if (SPI_MODE_SLAVE == obj->mode) {
SET_PERI_REG_MASK(SPI_DMA_CONF_REG(obj->spi_num), SPI_DMA_RX_STOP);
}
spi_dma_disable(obj);
}
#endif
/**
* @brief Based on pAttr initialize SPI module.
*
*/
void spi_init(spi_num_t spiNum, spi_attr_t* pAttr)
{
if ((spiNum > SPI_NUM_MAX)
|| (NULL == pAttr)) {
return;
}
SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_SPI_CLK_EN);
CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_SPI_RST);
SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_SPI_CLK_EN_1);
CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_SPI_RST_1);
SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_SPI_CLK_EN_2);
CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_SPI_RST_2);
CLEAR_PERI_REG_MASK(SPI_SLAVE_REG(spiNum), SPI_TRANS_DONE << 5);
SET_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_CS_SETUP);
// By default clear command
CLEAR_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_USR_COMMAND);
// SPI_CPOL & SPI_CPHA
switch (pAttr->sub_mode) {
case SPI_SUBMODE_1:
CLEAR_PERI_REG_MASK(SPI_PIN_REG(spiNum), SPI_CK_IDLE_EDGE);
SET_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_CK_OUT_EDGE); // CHPA_FALLING_EDGE_SAMPLE
break;
case SPI_SUBMODE_2:
SET_PERI_REG_MASK(SPI_PIN_REG(spiNum), SPI_CK_IDLE_EDGE);
SET_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_CK_OUT_EDGE); // CHPA_FALLING_EDGE_SAMPLE
break;
case SPI_SUBMODE_3:
SET_PERI_REG_MASK(SPI_PIN_REG(spiNum), SPI_CK_IDLE_EDGE);
CLEAR_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_CK_OUT_EDGE);
break;
case SPI_SUBMODE_0:
default:
CLEAR_PERI_REG_MASK(SPI_PIN_REG(spiNum), SPI_CK_IDLE_EDGE);
CLEAR_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_CK_OUT_EDGE);
// To do nothing
break;
}
// SPI bit order
if (SPI_BIT_ORDER_MSB_FIRST == pAttr->bit_order) {
CLEAR_PERI_REG_MASK(SPI_CTRL_REG(spiNum), SPI_WR_BIT_ORDER);
CLEAR_PERI_REG_MASK(SPI_CTRL_REG(spiNum), SPI_RD_BIT_ORDER);
} else if (SPI_BIT_ORDER_LSB_FIRST == pAttr->bit_order) {
SET_PERI_REG_MASK(SPI_CTRL_REG(spiNum), SPI_WR_BIT_ORDER);
SET_PERI_REG_MASK(SPI_CTRL_REG(spiNum), SPI_RD_BIT_ORDER);
} else {
// To do nothing
}
// SPI bit order
if (SPI_WORK_MODE_HALF == pAttr->half_mode) {
CLEAR_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_DOUTDIN);
} else if (SPI_WORK_MODE_FULL == pAttr->half_mode) {
SET_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_DOUTDIN);
}
// May be not must to do.
WRITE_PERI_REG(SPI_USER1_REG(spiNum), 0);
// SPI mode type
if (SPI_MODE_MASTER == pAttr->mode) {
// SPI mode type
SET_PERI_REG_BITS(SPI_CTRL2_REG(spiNum), SPI_MISO_DELAY_MODE, 0, SPI_MISO_DELAY_MODE_S); ////??????
// SPI_SET_MISO_DELAY_NUM(spiNum,0);////???????
//SET_PERI_REG_BITS(SPI_CTRL2_REG(spiNum), SPI_MISO_DELAY_NUM,0,SPI_MISO_DELAY_NUM_S);////??????
CLEAR_PERI_REG_MASK(SPI_SLAVE_REG(spiNum), SPI_SLAVE_MODE);
// SPI Send buffer
// CLEAR_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_USR_MISO_HIGHPART );// By default slave send buffer C0-C7
// SPI Speed
if (1 < (pAttr->speed)) {
uint8_t i, k;
i = (pAttr->speed / 40) ? (pAttr->speed / 40) : 1;
k = pAttr->speed / i;
CLEAR_PERI_REG_MASK(SPI_CLOCK_REG(spiNum), SPI_CLK_EQU_SYSCLK);
WRITE_PERI_REG(SPI_CLOCK_REG(spiNum),
(((i - 1) & SPI_CLKDIV_PRE) << SPI_CLKDIV_PRE_S) |
(((k - 1) & SPI_CLKCNT_N) << SPI_CLKCNT_N_S) |
((((k + 1) / 2 - 1) & SPI_CLKCNT_H) << SPI_CLKCNT_H_S) |
(((k - 1) & SPI_CLKCNT_L) << SPI_CLKCNT_L_S)); //clear bit 31,set SPI clock div
} else {
WRITE_PERI_REG(SPI_CLOCK_REG(spiNum), SPI_CLK_EQU_SYSCLK); // 80Mhz speed
}
// Enable MOSI
SET_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_CS_SETUP | SPI_CS_HOLD | SPI_USR_MOSI);
// CLEAR_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_CS_HOLD);/////////////add
SET_PERI_REG_MASK(SPI_CTRL2_REG(spiNum), ((0x4 & SPI_MISO_DELAY_NUM) << SPI_MISO_DELAY_NUM_S)); //delay num
} else if (SPI_MODE_SLAVE == pAttr->mode) {
// SPI mode type
SET_PERI_REG_MASK(SPI_SLAVE_REG(spiNum), SPI_SLAVE_MODE);
// SPI mode type
SET_PERI_REG_MASK(SPI_SLAVE_REG(spiNum), SPI_SLV_WR_RD_BUF_EN);
// SPI Send buffer
// SET_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_USR_MISO_HIGHPART);// By default slave send buffer C8-C15
// If do not set delay cycles, slave not working,master cann't get the data.
SET_PERI_REG_MASK(SPI_CTRL2_REG(spiNum), ((0x2 & SPI_MOSI_DELAY_NUM) << SPI_MOSI_DELAY_NUM_S)); //delay num
// SPI Speed
WRITE_PERI_REG(SPI_CLOCK_REG(spiNum), 0);
CLEAR_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_CS_SETUP);/////////////add
SET_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_USR_MOSI);
// By default format::CMD(8bits)+ADDR(8bits)+DATA(32bytes)
// set pAttr->cmd_len bit slave recieve command length
// set 1 bytes status buffer length
// set pAttr->addr_len bit slave recieve read address length
// set pAttr->addr_len bit slave recieve write address length
// set 32 bytes slave recieve buffer length
SET_PERI_REG_BITS(SPI_USER2_REG(spiNum), SPI_USR_COMMAND_BITLEN,
(7), SPI_USR_COMMAND_BITLEN_S);
SET_PERI_REG_BITS(SPI_SLAVE1_REG(spiNum), SPI_SLV_STATUS_BITLEN,
(7), SPI_SLV_STATUS_BITLEN_S);
SET_PERI_REG_BITS(SPI_SLAVE1_REG(spiNum), SPI_SLV_WR_ADDR_BITLEN,
(7), SPI_SLV_WR_ADDR_BITLEN_S);
SET_PERI_REG_BITS(SPI_SLAVE1_REG(spiNum), SPI_SLV_RD_ADDR_BITLEN,
(7), SPI_SLV_RD_ADDR_BITLEN_S);
SET_PERI_REG_BITS(SPI_SLV_WRBUF_DLEN_REG(spiNum), SPI_SLV_WRBUF_DBITLEN,
(32 * 8 - 1), SPI_SLV_WRBUF_DBITLEN_S);
SET_PERI_REG_BITS(SPI_SLV_RDBUF_DLEN_REG(spiNum), SPI_SLV_RDBUF_DBITLEN,
(32 * 8 - 1), SPI_SLV_RDBUF_DBITLEN_S);
} else {
// To do nothing
}
char i;
for (i = 0; i < 16; ++i) {
WRITE_PERI_REG((SPI_W0_REG(spiNum) + (i << 2)), 0);
}
}
/**
* @brief Set address value by master mode.
*
*/
void spi_master_cfg_addr(spi_num_t spiNum, uint32_t addr)
{
if (spiNum > SPI_NUM_MAX) {
return;
}
// Set address
SET_PERI_REG_BITS(SPI_ADDR_REG(spiNum), SPI_USR_ADDR_VALUE, addr, SPI_USR_ADDR_VALUE_S);
}
/**
* @brief Set command value by master mode.
*
*/
void spi_master_cfg_cmd(spi_num_t spiNum, uint32_t cmd)
{
if (spiNum > SPI_NUM_MAX) {
return;
}
// SPI_USER2 bit28-31 is cmd length,cmd bit length is value(0-15)+1,
// bit15-0 is cmd value.
SET_PERI_REG_BITS(SPI_USER2_REG(spiNum), SPI_USR_COMMAND_VALUE, cmd, SPI_USR_COMMAND_VALUE_S);
}
/**
* @brief Send data to slave.
*
*/
int spi_master_send_data(spi_num_t spiNum, spi_data_t* pInData)
{
char idx = 0;
if ((spiNum > SPI_NUM_MAX)
|| (NULL == pInData)
|| (64 < pInData->tx_data_len)) {
return -1;
}
uint32_t *value = pInData->tx_data;
while (READ_PERI_REG(SPI_CMD_REG(spiNum))&SPI_USR);
// Set command by user.
if (pInData->cmd_len != 0) {
// Max command length 16 bits.
SET_PERI_REG_BITS(SPI_USER2_REG(spiNum), SPI_USR_COMMAND_BITLEN,
((pInData->cmd_len << 3) - 1), SPI_USR_COMMAND_BITLEN_S);
// Enable command
SET_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_USR_COMMAND);
// Load command
spi_master_cfg_cmd(spiNum, pInData->cmd);
} else {
CLEAR_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_USR_COMMAND);
SET_PERI_REG_BITS(SPI_USER2_REG(spiNum), SPI_USR_COMMAND_BITLEN,
0, SPI_USR_COMMAND_BITLEN_S);
}
// Set Address by user.
if (pInData->addr_len == 0) {
CLEAR_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_USR_ADDR);
SET_PERI_REG_BITS(SPI_USER1_REG(spiNum), SPI_USR_ADDR_BITLEN,
0, SPI_USR_ADDR_BITLEN_S);
} else {
if (NULL == pInData->addr) {
return -1;
}
SET_PERI_REG_BITS(SPI_USER1_REG(spiNum), SPI_USR_ADDR_BITLEN,
((pInData->addr_len << 3) - 1), SPI_USR_ADDR_BITLEN_S);
// Enable address
SET_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_USR_ADDR);
// Load address
spi_master_cfg_addr(spiNum, *pInData->addr);
}
// Set data by user.
if (pInData->tx_data_len != 0) {
if (NULL == value) {
return -1;
}
CLEAR_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_USR_MISO);
// Enable MOSI
SET_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_USR_MOSI);
// Load send buffer
do {
WRITE_PERI_REG((SPI_W0_REG(spiNum) + (idx << 2)), *value++);
} while (++idx < ((pInData->tx_data_len / 4) + ((pInData->tx_data_len % 4) ? 1 : 0)));
// Set data send buffer length.Max data length 64 bytes.
SET_PERI_REG_BITS(SPI_MOSI_DLEN_REG(spiNum), SPI_USR_MOSI_DBITLEN, ((pInData->tx_data_len << 3) - 1), SPI_USR_MOSI_DBITLEN_S);
SET_PERI_REG_BITS(SPI_MISO_DLEN_REG(spiNum), SPI_USR_MISO_DBITLEN, ((pInData->rx_data_len << 3) - 1), SPI_USR_MISO_DBITLEN_S);
} else {
CLEAR_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_USR_MOSI);
CLEAR_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_USR_MISO);
SET_PERI_REG_BITS(SPI_MOSI_DLEN_REG(spiNum), SPI_USR_MOSI_DBITLEN,
0, SPI_USR_MOSI_DBITLEN_S);
}
// Start send data
SET_PERI_REG_MASK(SPI_CMD_REG(spiNum), SPI_USR);
while (!(READ_PERI_REG(SPI_SLAVE_REG(spiNum))&SPI_TRANS_DONE));
CLEAR_PERI_REG_MASK(SPI_SLAVE_REG(spiNum), SPI_TRANS_DONE);
return 0;
}
/**
* @brief Receive data from slave.
*
*/
int spi_master_recv_data(spi_num_t spiNum, spi_data_t* pData)
{
char idx = 0;
if ((spiNum > SPI_NUM_MAX)
|| (NULL == pData)) {
return -1;
}
uint32_t *value = pData->rx_data;
while (READ_PERI_REG(SPI_CMD_REG(spiNum))&SPI_USR);
// Set command by user.
if (pData->cmd_len != 0) {
// Max command length 16 bits.
SET_PERI_REG_BITS(SPI_USER2_REG(spiNum), SPI_USR_COMMAND_BITLEN,
((pData->cmd_len << 3) - 1), SPI_USR_COMMAND_BITLEN_S);
// Enable command
SET_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_USR_COMMAND);
// Load command
spi_master_cfg_cmd(spiNum, pData->cmd);
} else {
CLEAR_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_USR_COMMAND);
SET_PERI_REG_BITS(SPI_USER2_REG(spiNum), SPI_USR_COMMAND_BITLEN,
0, SPI_USR_COMMAND_BITLEN_S);
}
// Set Address by user.
if (pData->addr_len == 0) {
CLEAR_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_USR_ADDR);
SET_PERI_REG_BITS(SPI_USER1_REG(spiNum), SPI_USR_ADDR_BITLEN,
0, SPI_USR_ADDR_BITLEN_S);
} else {
if (NULL == pData->addr) {
return -1;
}
SET_PERI_REG_BITS(SPI_USER1_REG(spiNum), SPI_USR_ADDR_BITLEN,
((pData->addr_len << 3) - 1), SPI_USR_ADDR_BITLEN_S);
// Enable address
SET_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_USR_ADDR);
// Load address
spi_master_cfg_addr(spiNum, *pData->addr);
}
// Set data by user.
if (pData->rx_data_len != 0) {
if (NULL == value) {
return -1;
}
// Clear MOSI enable
CLEAR_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_USR_MOSI);
// Enable MOSI
SET_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_USR_MISO);
// Set data send buffer length.Max data length 64 bytes.
SET_PERI_REG_BITS(SPI_MISO_DLEN_REG(spiNum), SPI_USR_MISO_DBITLEN, ((pData->rx_data_len << 3) - 1), SPI_USR_MISO_DBITLEN_S);
} else {
CLEAR_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_USR_MOSI);
CLEAR_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_USR_MISO);
SET_PERI_REG_BITS(SPI_MISO_DLEN_REG(spiNum), SPI_USR_MISO_DBITLEN, 0, SPI_USR_MISO_DBITLEN_S);
}
// Start send data
SET_PERI_REG_MASK(SPI_CMD_REG(spiNum), SPI_USR);
while (READ_PERI_REG(SPI_CMD_REG(spiNum))&SPI_USR);
// Read data out
do {
*value++ = READ_PERI_REG(SPI_W0_REG(spiNum) + (idx << 2));
} while (++idx < ((pData->rx_data_len / 4) + ((pData->rx_data_len % 4) ? 1 : 0)));
return 0;
}
/**
* @brief Load data to send buffer by slave mode.
*
*/
int spi_slave_send_data(spi_num_t spiNum, uint32_t *pOutData, uint8_t outLen)
{
if (NULL == pOutData) {
return -1;
}
char i;
uint32_t *value = pOutData;
for (i = 0; i < outLen; ++i) {
WRITE_PERI_REG((SPI_W0_REG(spiNum) + (i << 2)), *value++);
}
return 0;
}
/**
* @brief Configurate slave prepare for receive data.
*
*/
int spi_slave_recv_data(spi_num_t spiNum, void(*isrFunc)(void*))
{
char idx = 0;
if (spiNum > SPI_NUM_MAX) {
return -1;
}
spi_int_enable(spiNum, SPI_INT_SRC_WR_STA_DONE
| SPI_INT_SRC_RD_STA_DONE | SPI_INT_SRC_WR_BUF_DONE | SPI_INT_SRC_RD_BUF_DONE);
spi_int_disable(spiNum, SPI_INT_SRC_TRANS_DONE);
spi_intr_func_set(isrFunc, spiNum);
return 0;
}
/**
* @brief Send data to slave(ESP32,RD_STATUS or WR_STATUS).
*
*/
void spi_master_send_status(spi_num_t spiNum, uint8_t data)
{
if (spiNum > SPI_NUM_MAX) {
return;
}
while (READ_PERI_REG(SPI_CMD_REG(spiNum))&SPI_USR);
// enable MOSI
SET_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_USR_MOSI);
CLEAR_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_USR_MISO | SPI_USR_DUMMY | SPI_USR_ADDR);
// 8bits cmd, 0x04 is eps32 slave write cmd value
WRITE_PERI_REG(SPI_USER2_REG(spiNum),
((7 & SPI_USR_COMMAND_BITLEN) << SPI_USR_COMMAND_BITLEN_S)
| MASTER_WRITE_STATUS_TO_SLAVE_CMD);
// Set data send buffer length.
SET_PERI_REG_BITS(SPI_MOSI_DLEN_REG(spiNum), SPI_USR_MOSI_DBITLEN,
((sizeof(data) << 3) - 1), SPI_USR_MOSI_DBITLEN_S);
WRITE_PERI_REG(SPI_W0_REG(spiNum), (uint32_t)(data));
// start SPI
SET_PERI_REG_MASK(SPI_CMD_REG(spiNum), SPI_USR);
}
/**
* @brief Receive data from slave(ESP32).
*
*/
int spi_master_recv_status(spi_num_t spiNum)
{
if (spiNum > SPI_NUM_MAX) {
return -1;
}
while (READ_PERI_REG(SPI_CMD_REG(spiNum))&SPI_USR);
// enable MISO
SET_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_USR_MISO);
CLEAR_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_USR_MOSI | SPI_USR_DUMMY | SPI_USR_ADDR);
// 8bits cmd, 0x06 is eps32 slave read cmd value
WRITE_PERI_REG(SPI_USER2_REG(spiNum),
((7 & SPI_USR_COMMAND_BITLEN) << SPI_USR_COMMAND_BITLEN_S)
| MASTER_READ_STATUS_FROM_SLAVE_CMD);
// Set revcive buffer length.
SET_PERI_REG_BITS(SPI_MISO_DLEN_REG(spiNum), SPI_USR_MISO_DBITLEN,
7, SPI_USR_MISO_DBITLEN_S);
// start spi module.
SET_PERI_REG_MASK(SPI_CMD_REG(spiNum), SPI_USR);
while (READ_PERI_REG(SPI_CMD_REG(spiNum))&SPI_USR);
uint8_t data = (uint8_t)(READ_PERI_REG(SPI_W0_REG(spiNum)) & 0xff);
return (uint8_t)(READ_PERI_REG(SPI_W0_REG(spiNum)) & 0xff);
}
/**
* @brief Enable SPI interrupt source.
*
*/
void spi_int_enable(spi_num_t spiNum, spi_int_src_t intSrc)
{
if (spiNum > SPI_NUM_MAX) {
return;
}
SET_PERI_REG_MASK(SPI_SLAVE_REG(spiNum), intSrc << 4);
}
/**
* @brief Disable SPI interrupt source.
*
*/
void spi_int_disable(spi_num_t spiNum, spi_int_src_t intSrc)
{
if (spiNum > SPI_NUM_MAX) {
return;
}
CLEAR_PERI_REG_MASK(SPI_SLAVE_REG(spiNum), intSrc);
}
/**
* @brief Clear all of SPI interrupt source.
*
*/
void spi_int_clear(spi_num_t spiNum)
{
if (spiNum > SPI_NUM_MAX) {
return;
}
CLEAR_PERI_REG_MASK(SPI_SLAVE_REG(spiNum), SPI_INT_SRC_TRANS_DONE
| SPI_INT_SRC_WR_STA_DONE
| SPI_INT_SRC_RD_STA_DONE
| SPI_INT_SRC_WR_BUF_DONE
| SPI_INT_SRC_RD_BUF_DONE);
}
/**
* @brief Get the SPI interrupt status.
*
*/
int32_t spi_int_status_get(spi_num_t i2sNum)
{
if (i2sNum > SPI_NUM_MAX) {
return -1;
}
return READ_PERI_REG(SPI_SLAVE_REG(i2sNum));
}
#ifdef __cplusplus
}
#endif