Skip to content

Commit

Permalink
[beken-72xx] Add draft SPI TX support
Browse files Browse the repository at this point in the history
  • Loading branch information
kuba2k2 committed Mar 26, 2024
1 parent c099503 commit 7630a23
Show file tree
Hide file tree
Showing 4 changed files with 343 additions and 0 deletions.
198 changes: 198 additions & 0 deletions cores/beken-72xx/arduino/libraries/SPI/SPI.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,198 @@
/* Copyright (c) Kuba Szczodrzyński 2024-03-15. */

#include "SPIPrivate.h"

#define SPI_PERI_CLK_26M (26 * 1000 * 1000)
#define SPI_PERI_CLK_DCO (80 * 1000 * 1000)

bool SPIClass::beginPrivate() {
if (!this->data)
return false;
uint32_t param;

REG_SPI0->ctrl = 0;

intc_service_change_handler(IRQ_SPI, (FUNCPTR)SPIClass::isrHandlerStatic);
// bk_spi_configure()
REG_SPI0->BIT_WIDTH = 0;
REG_SPI0->MSTEN = true;
// disable hardware CS - issues with per-byte data transfer otherwise
#if LT_BK7231N
REG_SPI0->WIRE3_EN = true;
#else
REG_SPI0->NSSMD = 3;
#endif
// spi_init_msten(0)
REG_SPI0->TX_FIFO_INT_LEVEL = 0;
REG_SPI0->TX_FIFO_INT_LEVEL = 0;
REG_SPI0->TX_UDF_INT_EN = true;
REG_SPI0->RX_OVF_INT_EN = true;
// spi_active(1)
REG_SPI0->SPIEN = true;
// spi_icu_configuration(1)
param = PWD_SPI_CLK_BIT;
icu_ctrl(CMD_CLK_PWR_UP, &param);
param = IRQ_SPI_BIT;
icu_ctrl(CMD_ICU_INT_ENABLE, &param);
// spi_gpio_configuration()
param = GFUNC_MODE_SPI;
gpio_ctrl(CMD_GPIO_ENABLE_SECOND, &param);

return true;
}

bool SPIClass::endPrivate() {
if (!this->data)
return true;
uint32_t param;

param = IRQ_SPI_BIT;
icu_ctrl(CMD_ICU_INT_DISABLE, &param);
param = PWD_SPI_CLK_BIT;
icu_ctrl(CMD_CLK_PWR_DOWN, &param);

REG_SPI0->ctrl = 0;

return true;
}

void SPIClass::setFrequency(uint32_t frequency) {
if (!this->data)
return;
uint32_t param;
uint32_t maxFrequency = 30000000;
uint32_t sourceClk;
uint32_t clockDiv;

REG_SPI0->SPIEN = false;
this->settings._clock = frequency;

if (frequency == 26000000 || frequency == 13000000 || frequency == 6500000 || frequency <= 4333000) {
#if CFG_XTAL_FREQUENCE
sourceClk = CFG_XTAL_FREQUENCE;
#else
sourceClk = SPI_PERI_CLK_26M;
#endif
param = PCLK_POSI_SPI;
icu_ctrl(CMD_CONF_PCLK_26M, &param);
} else {
if (frequency > maxFrequency) {
LT_WM(SPI, "Clock freq too high! %lu > %lu", frequency, maxFrequency);
frequency = maxFrequency;
}
sourceClk = SPI_PERI_CLK_DCO;
param = PWD_SPI_CLK_BIT;
icu_ctrl(CMD_CLK_PWR_DOWN, &param);
param = PCLK_POSI_SPI;
icu_ctrl(CMD_CONF_PCLK_DCO, &param);
param = PWD_SPI_CLK_BIT;
icu_ctrl(CMD_CLK_PWR_UP, &param);
}

if (frequency == 26000000 || frequency == 13000000 || frequency == 6500000) {
clockDiv = sourceClk / frequency - 1;
} else {
clockDiv = ((sourceClk >> 1) / frequency);
if (clockDiv < 2)
clockDiv = 2;
else if (clockDiv >= 255)
clockDiv = 255;
}

REG_SPI0->SPI_CKR = clockDiv;
REG_SPI0->SPIEN = true;
}

void SPIClass::setBitOrder(uint8_t bitOrder) {
if (!this->data)
return;
this->settings._bitOrder = bitOrder;
#if LT_BK7231N
REG_SPI0->LSB_FIRST = bitOrder == SPI_LSBFIRST;
#endif
}

void SPIClass::setDataMode(uint8_t dataMode) {
if (!this->data)
return;
this->settings._dataMode = dataMode;
REG_SPI0->CKPOL = (dataMode >> 1) & 0b1;
REG_SPI0->CKPHA = (dataMode >> 0) & 0b1;
}

void SPIClass::commitTransaction() {
if (this->txLen != 0) {
REG_SPI0->TX_FIFO_CLR = true;
REG_SPI0->TX_TRANS_LEN = this->txLen * 8;
REG_SPI0->TX_FIFO_INT_EN = false;
REG_SPI0->TX_EN = true;
while (this->txLen--) {
while (REG_SPI0->TX_FIFO_WR_READY == false) {}
uint32_t data = *this->txBuf++;
// LT_I("<- TX: %02x", data);
REG_SPI0->SPI_DAT = data;
}
REG_SPI0->TX_FIFO_INT_EN = false;
REG_SPI0->TX_EN = false;
}
if (this->rxLen != 0) {
// REG_SPI0->RX_FIFO_CLR = true;
// REG_SPI0->RX_TRANS_LEN = this->rxLen * 8;
// REG_SPI0->RX_FIFO_INT_EN = false;
// REG_SPI0->RX_FINISH_INT_EN = false;
// REG_SPI0->RX_EN = true;
// while (this->rxLen--) {
// while (REG_SPI0->RX_FIFO_RD_READY == false) {}
// uint32_t data = REG_SPI0->SPI_DAT;
// // LT_I("-> RX: %02x", data);
// *this->rxBuf++ = data;
// }
// REG_SPI0->RX_EN = false;
// REG_SPI0->TX_FIFO_INT_EN = false;
// REG_SPI0->RX_FIFO_INT_EN = false;
}
}

void SPIClass::isrHandlerStatic(void *param) {
SPI.isrHandler(param);
}

void SPIClass::isrHandler(void *param) {
if (REG_SPI0->RX_FIFO_INT) {
LT_I("RX_FIFO_INT, rxLen=%d", this->rxLen);
while (this->rxLen != 0 && REG_SPI0->RX_FIFO_RD_READY == true) {
uint8_t data = REG_SPI0->SPI_DAT;
LT_I("RX data in ISR #1 %02x", data);
*this->rxBuf++ = data;
this->rxLen--;
}
if (this->rxLen == 0) {
REG_SPI0->RX_EN = false;
REG_SPI0->TX_FIFO_INT_EN = false;
REG_SPI0->RX_FIFO_INT_EN = false;
}
REG_SPI0->RX_FIFO_INT = true;
}
if (REG_SPI0->RX_FINISH_INT) {
LT_I("RX_FINISH_INT, rxLen=%d", this->rxLen);
while (this->rxLen != 0 && REG_SPI0->RX_FIFO_RD_READY == true) {
uint8_t data = REG_SPI0->SPI_DAT;
LT_I("RX data in ISR #2 %02x", data);
*this->rxBuf++ = data;
this->rxLen--;
}
REG_SPI0->RX_EN = false;
REG_SPI0->TX_FIFO_INT_EN = false;
REG_SPI0->RX_FIFO_INT_EN = false;
REG_SPI0->RX_FINISH_INT = true;
}

if (REG_SPI0->TX_UDF_INT) {
LT_W("TX underflow");
REG_SPI0->TX_UDF_INT = true;
}
if (REG_SPI0->RX_OVF_INT) {
LT_W("RX overflow");
REG_SPI0->RX_OVF_INT = true;
}
}
143 changes: 143 additions & 0 deletions cores/beken-72xx/arduino/libraries/SPI/SPIPrivate.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
/* Copyright (c) Kuba Szczodrzyński 2024-03-15. */

#pragma once

#include <ArduinoPrivate.h>
#include <SPI.h>

struct SPIData {};

// Register structures based on:
// - https://github.com/bekencorp/armino/blob/main/middleware/soc/bk7231n/soc/spi_struct.h
// - https://wiki.bekencorp.com/pages/viewpage.action?pageId=23692278
// - BDK beken378/driver/spi/*.h

typedef volatile struct {
union {
struct {
uint32_t TX_FIFO_INT_LEVEL : 2; //!< TX FIFO interrupt generation condition (1/16/32/48) [RW] (0x0[0:1])
uint32_t RX_FIFO_INT_LEVEL : 2; //!< RX FIFO interrupt generation condition (1/16/32/48) [RW] (0x0[2:3])
uint32_t TX_UDF_INT_EN : 1; //!< TX FIFO underflow interrupt enable [RW] (0x0[4])
uint32_t RX_OVF_INT_EN : 1; //!< RX FIFO overflow interrupt enable [RW] (0x0[5])
uint32_t TX_FIFO_INT_EN : 1; //!< TX FIFO interrupt enable [RW] (0x0[6])
uint32_t RX_FIFO_INT_EN : 1; //!< RX FIFO interrupt enable [RW] (0x0[7])
uint32_t SPI_CKR : 8; //!< Prescaler factor [RW] (0x0[8:15])
#if LT_BK7231N || LT_BK7271
uint32_t SLV_RELEASE_INT_EN : 1; //!< Slave release interrupt enable (four-wire slave mode) [RW] (0x0[16])
uint32_t WIRE3_EN : 1; //!< Three-wire mode (no CSN signal) [RW] (0x0[17])
#else
uint32_t NSSMD : 2; //!< (0x0[16:17])
#endif
uint32_t BIT_WIDTH : 1; //!< Data bit width (0: 8-bit, 1: 16-bit) [RW] (0x0[18])
#if LT_BK7231N || LT_BK7271
uint32_t LSB_FIRST : 1; //!< Data frame format (0: MSB-first, 1: LSB-first) [RW] (0x0[19])
#else
uint32_t _reserved0 : 1; //!< (0x0[19])
#endif
uint32_t CKPOL : 1; //!< SPI clock polarity [RW] (0x0[20])
uint32_t CKPHA : 1; //!< SPI clock phase [RW] (0x0[21])
uint32_t MSTEN : 1; //!< Master mode enable [RW] (0x0[22])
uint32_t SPIEN : 1; //!< SPI enable [RW] (0x0[23])
#if LT_BK7231N || LT_BK7271
uint32_t BYTE_INTLVAL : 8; //!< SCK interval between data units (master) [RW] (0x0[24:31])
#else
uint32_t _reserved1 : 8; //!< (0x0[24:31])
#endif
};

uint32_t ctrl;
};

#if LT_BK7231N || LT_BK7271
union {
struct {
uint32_t TX_EN : 1; //!< TX enable [RW] (0x1[0])
uint32_t RX_EN : 1; //!< RX enable [RW] (0x1[1])
uint32_t TX_FINISH_INT_EN : 1; //!< TX_TRANS_LEN completed interrupt enabled [RW] (0x1[2])
uint32_t RX_FINISH_INT_EN : 1; //!< RX_TRANS_LEN completed interrupt enable [RW] (0x1[3])
uint32_t _reserved2 : 4; //!< (0x1[4:7])
uint32_t TX_TRANS_LEN : 12; //!< TX data length (bits), 0: unlimited [RW] (0x1[8:19])
uint32_t RX_TRANS_LEN : 12; //!< RX data length (bits), 0: unlimited [RW] (0x1[20:31])
};

uint32_t config;
};
#endif

#if LT_BK7231N || LT_BK7271
union {
struct {
uint32_t _reserved3 : 1; //!< (0x2[0])
uint32_t TX_FIFO_WR_READY : 1; //!< TX FIFO write allowed [R] (0x2[1])
uint32_t RX_FIFO_RD_READY : 1; //!< RX FIFO read allowed [R] (0x2[2])
uint32_t _reserved4 : 1; //!< (0x2[3])
uint32_t _reserved5 : 4; //!< (0x2[4:7])
uint32_t TX_FIFO_INT : 1; //!< TX FIFO interrupt (1: clear) [RW] (0x2[8])
uint32_t RX_FIFO_INT : 1; //!< RX FIFO interrupt (1: clear) [RW] (0x2[9])
uint32_t SLV_RELEASE_INT : 1; //!< Slave release interrupt (1: clear) [RW] (0x2[10])
uint32_t TX_UDF_INT : 1; //!< TX FIFO underflow interrupt (1: clear) [RW] (0x2[11])
uint32_t RX_OVF_INT : 1; //!< RX FIFO overflow interrupt (1: clear) [RW] (0x2[12])
uint32_t TX_FINISH_INT : 1; //!< TX_TRANS_LEN completed interrupt [R] (0x2[13])
uint32_t RX_FINISH_INT : 1; //!< RX_TRANS_LEN completed interrupt [R] (0x2[14])
uint32_t _reserved6 : 1; //!< (0x2[15])
uint32_t TX_FIFO_CLR : 1; //!< TX FIFO clear enable [W] (0x2[16])
uint32_t RX_FIFO_CLR : 1; //!< RX FIFO clear enable [W] (0x2[17])
uint32_t _reserved7 : 14; //!< (0x2[18:31])
};

uint32_t status;
};
#else
union {
struct {
uint32_t TX_FIFO_EMPTY : 1; //!< (0x1[0])
uint32_t TX_FIFO_FULL : 1; //!< (0x1[1])
uint32_t RX_FIFO_EMPTY : 1; //!< (0x1[2])
uint32_t RX_FIFO_FULL : 1; //!< (0x1[3])
uint32_t _reserved8 : 4; //!< (0x2[4:7])
uint32_t TX_FIFO_INT : 1; //!< TX FIFO interrupt (1: clear) [RW] (0x2[8])
uint32_t RX_FIFO_INT : 1; //!< RX FIFO interrupt (1: clear) [RW] (0x2[9])
uint32_t MODF : 1; //!< (0x1[10])
uint32_t TX_UDF_INT : 1; //!< TX FIFO underflow interrupt (1: clear) [RW] (0x2[11])
uint32_t RX_OVF_INT : 1; //!< RX FIFO overflow interrupt (1: clear) [RW] (0x2[12])
uint32_t _reserved9 : 1; //!< (0x1[13])
uint32_t SLVSEL : 1; //!< (0x1[14])
uint32_t SPIBUSY : 1; //!< (0x1[15])
uint32_t _reserved10 : 16; //!< (0x1[16:31])
};

uint32_t status;
};
#endif

union {
struct {
uint32_t SPI_DAT : 16; //!< FIFO read/write operation [RW] (0x2[0:15])
uint32_t _reserved11 : 16; //!< (0x2[16:31])
};

uint32_t data;
};

#if !(LT_BK7231N || LT_BK7271)
union {
struct {
uint32_t _reserved12 : 1; //!< (0x3[0])
uint32_t S_CS_UP_INT_EN : 1; //!< (0x3[1])
uint32_t _reserved13 : 2; //!< (0x3[2:3])
uint32_t S_CS_UP_INT_STATUS : 1; //!< (0x3[4])
uint32_t _reserved14 : 27; //!< (0x3[5:31])
};

uint32_t slave_ctrl;
};
#endif
} spi_hw_t;

#if LT_BK7271
#define REG_SPI0 ((spi_hw_t *)0x00802500)
#define REG_SPI1 ((spi_hw_t *)0x00802540)
#define REG_SPI2 ((spi_hw_t *)0x00802580)
#else
#define REG_SPI0 ((spi_hw_t *)0x00802700)
#endif
1 change: 1 addition & 0 deletions cores/beken-72xx/arduino/src/lt_defs.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@

#define LT_ARD_HAS_WIFI 1
#define LT_ARD_HAS_SERIAL 1
#define LT_ARD_HAS_SPI 1
#define LT_ARD_HAS_WIRE 1
#define LT_ARD_MD5_HOSTAPD 1
1 change: 1 addition & 0 deletions cores/beken-72xx/base/sdk_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ extern "C" {
#include <pwm_pub.h>
#include <rtos_pub.h>
#include <saradc_pub.h>
#include <spi_pub.h>
#include <start_type_pub.h>
#include <sys_ctrl.h>
#include <sys_rtos.h>
Expand Down

0 comments on commit 7630a23

Please sign in to comment.