Firmwares/raven/src/io/spi.h

201 lines
5.0 KiB
C++

/*
* spi.h
*
* Created on: 29.07.2018
* Author: eyck
*/
#ifndef SPI_H_
#define SPI_H_
#include <sifive/devices/spi.h>
#include "util/bit_field.h"
#include <array>
#include <cstdint>
template<uint32_t BASE_ADDR>
class spi_regs {
public:
// storage declarations
BEGIN_BF_DECL(sckdiv_t, uint32_t);
BF_FIELD(div, 0, 12);
END_BF_DECL();
BEGIN_BF_DECL(sckmode_t, uint32_t);
BF_FIELD(pha, 0, 1);
BF_FIELD(pol, 1, 1);
END_BF_DECL();
uint32_t r_csid;
uint32_t r_csdef;
BEGIN_BF_DECL(csmode_t, uint32_t);
BF_FIELD(mode, 0, 2);
END_BF_DECL();
BEGIN_BF_DECL(delay0_t, uint32_t);
BF_FIELD(cssck, 0, 8);
BF_FIELD(sckcs, 16, 8);
END_BF_DECL();
BEGIN_BF_DECL(delay1_t, uint32_t);
BF_FIELD(intercs, 0, 16);
BF_FIELD(interxfr, 16, 8);
END_BF_DECL();
BEGIN_BF_DECL(fmt_t, uint32_t);
BF_FIELD(proto, 0, 2);
BF_FIELD(endian, 2, 1);
BF_FIELD(dir, 3, 1);
BF_FIELD(len, 16, 4);
END_BF_DECL();
BEGIN_BF_DECL(txdata_t, uint32_t);
BF_FIELD(data, 0, 8);
BF_FIELD(full, 31, 1);
END_BF_DECL() r_txdata;
BEGIN_BF_DECL(rxdata_t, uint32_t);
BF_FIELD(data, 0, 8);
BF_FIELD(empty, 31, 1);
END_BF_DECL();
BEGIN_BF_DECL(txmark_t, uint32_t);
BF_FIELD(txmark, 0, 3);
END_BF_DECL();
BEGIN_BF_DECL(rxmark_t, uint32_t);
BF_FIELD(rxmark, 0, 3);
END_BF_DECL();
BEGIN_BF_DECL(fctrl_t, uint32_t);
BF_FIELD(en, 0, 1);
END_BF_DECL();
BEGIN_BF_DECL(ffmt_t, uint32_t);
BF_FIELD(cmd_en, 0, 1);
BF_FIELD(addr_len, 1, 2);
BF_FIELD(pad_cnt, 3, 4);
BF_FIELD(cmd_proto, 7, 2);
BF_FIELD(addr_proto, 9, 2);
BF_FIELD(data_proto, 11, 2);
BF_FIELD(cmd_code, 16, 8);
BF_FIELD(pad_code, 24, 8);
END_BF_DECL();
BEGIN_BF_DECL(ie_t, uint32_t);
BF_FIELD(txwm, 0, 1);
BF_FIELD(rxwm, 1, 1);
END_BF_DECL();
BEGIN_BF_DECL(ip_t, uint32_t);
BF_FIELD(txwm, 0, 1);
BF_FIELD(rxwm, 1, 1);
END_BF_DECL();
static inline sckdiv_t& sckdiv_reg(){
return *reinterpret_cast<sckdiv_t*>(BASE_ADDR+SPI_REG_SCKDIV);
}
static inline sckmode_t& sckmode_reg(){
return *reinterpret_cast<sckmode_t*>(BASE_ADDR+SPI_REG_SCKMODE);
}
static inline uint32_t& csid_reg(){
return *reinterpret_cast<uint32_t*>(BASE_ADDR+SPI_REG_CSID);
}
static inline uint32_t& csdef_reg(){
return *reinterpret_cast<uint32_t*>(BASE_ADDR+SPI_REG_CSDEF);
}
static inline csmode_t& csmode_reg(){
return *reinterpret_cast<csmode_t*>(BASE_ADDR+SPI_REG_CSMODE);
}
static inline delay0_t& dcssck_reg(){
return *reinterpret_cast<delay0_t*>(BASE_ADDR+SPI_REG_DCSSCK);
}
static inline uint32_t& dsckcs_reg(){
return *reinterpret_cast<uint32_t*>(BASE_ADDR+SPI_REG_DSCKCS);
}
static inline delay1_t& dintercs_reg(){
return *reinterpret_cast<delay1_t*>(BASE_ADDR+SPI_REG_DINTERCS);
}
static inline uint32_t& dinterxfr_reg(){
return *reinterpret_cast<uint32_t*>(BASE_ADDR+SPI_REG_DINTERXFR);
}
static inline fmt_t& fmt_reg(){
return *reinterpret_cast<fmt_t*>(BASE_ADDR+SPI_REG_FMT);
}
static inline txdata_t& txfifo_reg(){
return *reinterpret_cast<txdata_t*>(BASE_ADDR+SPI_REG_TXFIFO);
}
static inline rxdata_t& rxfifo_reg(){
return *reinterpret_cast<rxdata_t*>(BASE_ADDR+SPI_REG_RXFIFO);
}
static inline txmark_t& txctrl_reg(){
return *reinterpret_cast<txmark_t*>(BASE_ADDR+SPI_REG_TXCTRL);
}
static inline rxmark_t& rxctrl_reg(){
return *reinterpret_cast<rxmark_t*>(BASE_ADDR+SPI_REG_RXCTRL);
}
static inline fctrl_t& fctrl_reg(){
return *reinterpret_cast<fctrl_t*>(BASE_ADDR+SPI_REG_FCTRL);
}
static inline ffmt_t& ffmt_reg(){
return *reinterpret_cast<ffmt_t*>(BASE_ADDR+SPI_REG_FFMT);
}
static inline ie_t& ie_reg(){
return *reinterpret_cast<ie_t*>(BASE_ADDR+SPI_REG_IE);
}
static inline ip_t& ip_reg(){
return *reinterpret_cast<ip_t*>(BASE_ADDR+SPI_REG_IP);
}
template<size_t SIZE>
static bool transfer(std::array<uint8_t, SIZE>& bytes){
csmode_reg().mode=2; // HOLD mode
rxctrl_reg().rxmark=bytes.size()-1; // trigger irq if more than 2 bytes are received;
ie_reg().rxwm=1;
// write data bytes
for(size_t i=0; i<bytes.size(); ++i)
txfifo_reg()=bytes[i];
// wait until SPI is done
spi_active=true;
do{
asm("wfi");
asm("nop");
}while(spi_active);
// deactivate SPI
csmode_reg().mode=0; // AUTO mode, deactivates CS
// fetch results
for(size_t i=0; i<bytes.size(); ++i) bytes[i]=rxfifo_reg();
return true;
}
static void spi_rx_interrupt_handler(){
ip_reg().rxwm=0;
ie_reg().rxwm=0;
spi_active=false;
}
private:
static volatile bool spi_active;
};
#endif /* SPI_H_ */