2018-08-08 20:59:10 +02:00
|
|
|
/*
|
|
|
|
* 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"
|
2018-09-14 14:03:20 +02:00
|
|
|
#include <array>
|
2018-08-08 20:59:10 +02:00
|
|
|
#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);
|
|
|
|
}
|
|
|
|
|
2018-09-14 14:03:20 +02:00
|
|
|
template<size_t SIZE>
|
|
|
|
static bool transfer(std::array<uint8_t, SIZE>& bytes){
|
|
|
|
csmode_reg().mode=2; // HOLD mode
|
2018-10-05 12:23:39 +02:00
|
|
|
rxctrl_reg().rxmark=bytes.size()-1; // trigger irq if more than 2 bytes are received;
|
2018-09-14 14:03:20 +02:00
|
|
|
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;
|
2018-08-08 20:59:10 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
#endif /* SPI_H_ */
|