Skip to content
Snippets Groups Projects
Commit 11901f59 authored by Thomas Owen James's avatar Thomas Owen James :speech_balloon:
Browse files

Micron board and Bril support

parent 1357c7b4
No related branches found
No related tags found
No related merge requests found
Showing
with 1914 additions and 13 deletions
......@@ -8,9 +8,22 @@
# "wzdma" for DMA driver from Wojciech M. Zabolotny
# "dma" for XILINX DMA driver
# "filedma" for reading from file and simulating DMA
#
# "micronDMA" for PICO driver
input:wzdma
# Settings for Micron board only
loadBitFile:yes
# ONLY for Micron Board/DMA, must be in tgz format, produced by pico utility package_flash
bitFileName:micron_bitfile_path
## Settings for DMA input
# DMA device
......
......@@ -174,7 +174,7 @@ BuildArch: $BUILD_ARCH
AutoReqProv: no
Provides:/opt/scdaq
Requires: tbb boost-thread libcurl
Requires: tbb boost-thread libcurl libcrypto
%description
scouting daq
......
......@@ -12,7 +12,7 @@
TARGET = scdaq
# source files
SOURCES = config.cc DmaInputFilter.cc elastico.cc FileDmaInputFilter.cc InputFilter.cc output.cc processor.cc scdaq.cc session.cc slice.cc WZDmaInputFilter.cc
SOURCES = config.cc DmaInputFilter.cc elastico.cc FileDmaInputFilter.cc InputFilter.cc output.cc processor.cc scdaq.cc session.cc slice.cc WZDmaInputFilter.cc MicronDmaInputFilter.cc
C_SOURCES = wz_dma.c
# work out names of object files from sources
......@@ -27,7 +27,7 @@ CXXFLAGS = -std=c++11 -Wall -Wextra -O0 -g -rdynamic -Wconversion
#CXXFLAGS = -std=c++11 -Wall -Wextra -g -rdynamic
CFLAGS = $(CXXFLAGS)
LDFLAGS = -ltbb -ltbbmalloc -lboost_thread -lboost_chrono -lcurl -pthread
LDFLAGS = -Llibmicron -ltbb -ltbbmalloc -lboost_thread -lboost_chrono -lcurl -lpthread -lcrypto
CPPFLAGS = -I. -Iwzdma
......@@ -43,7 +43,7 @@ clean:
# dependencies separated by spaces (duplicates removed),
# here ${OBJECTS}
${TARGET}: ${OBJECTS}
${LINK.cc} -o $@ $^
${LINK.cc} -o $@ $^ -lmicron
# no rule is needed here for compilation as make already
# knows how to do it
......@@ -64,8 +64,9 @@ elastico.o: elastico.h format.h slice.h controls.h log.h
FileDmaInputFilter.o: FileDmaInputFilter.h InputFilter.h log.h
InputFilter.o: InputFilter.h log.h
output.o: output.h slice.h log.h
processor.o: processor.h slice.h format.h log.h
processor.o: processor.h slice.h format.h log.h bril_histo.h
session.o: session.h log.h
slice.o: slice.h
WZDmaInputFilter.o: WZDmaInputFilter.h InputFilter.h tools.h log.h
wz_dma.o: wz_dma.h
MicronDmaInputFilter.o: MicronDmaInputFilter.h libmicron/micron_dma.h
#include "MicronDmaInputFilter.h"
#include <ctype.h>
#include <boost/multiprecision/cpp_int.hpp>
#include <cstring>
#include <system_error>
#include "format.h"
#include "log.h"
using uint256_t = boost::multiprecision::number<
boost::multiprecision::cpp_int_backend<256, 256, boost::multiprecision::unsigned_magnitude,
boost::multiprecision::unchecked, void>,
boost::multiprecision::et_off>;
MicronDmaInputFilter::MicronDmaInputFilter(size_t packetBufferSize, size_t nbPacketBuffers,
ctrl &control, config &conf)
: InputFilter(packetBufferSize, nbPacketBuffers, control) {
std::string bitFileName = conf.getBitFileName();
bool loadBitFile = conf.getLoadBitFile();
int err;
processorType_ = conf.getProcessorType();
// The RunBitFile function will locate a Pico card that can run the given bit
// file, and is not already
// opened in exclusive-access mode by another program. It requests exclusive
// access to the Pico card so no other programs will try to reuse the card
// and interfere with us.
if (loadBitFile) {
LOG(DEBUG) << "Loading FPGA with '" << bitFileName << "' ...";
err = micron_run_bit_file(bitFileName.c_str(), &pico_);
} else {
err = micron_find_pico(0x852, &pico_);
}
LOG(TRACE) << "Opening streams to and from the FPGA";
stream2_ = micron_create_stream(pico_, 2);
if (stream2_ < 0) {
// All functions in the Pico API return an error code. If that code is < 0,
// then you should use the PicoErrors_FullError function to decode the error
// message.
// fprintf(stderr, "%s: CreateStream error: %s\n", "bitfile",
// PicoErrors_FullError(stream1_, 0, packetBufferSize));
throw std::runtime_error(bitFileName + ": CreateStream error: " +
micron_picoerrors_fullerror(stream2_, 0, packetBufferSize));
}
LOG(TRACE) << "Created Micron DMA input filter";
}
MicronDmaInputFilter::~MicronDmaInputFilter() {
// streams are automatically closed when the PicoDrv object is destroyed, or
// on program termination, but
// we can also close a stream manually.
micron_close_stream(pico_, stream2_);
LOG(TRACE) << "Destroyed Micron DMA input filter";
}
// add pad bytes to next multiple of 16 bytes
int pad_for_16bytes(int len) {
int pad_len = len;
if (len % 16 != 0) {
pad_len = len + (16 - len % 16);
}
return pad_len;
}
// print <count> 256-bit numbers from buf
void print256(FILE *f, void *buf, int count) {
uint32_t *u32p = (uint32_t *)buf;
for (int i = 0; i < count; ++i) {
fprintf(f, "0x%08x_%08x_%08x_%08x_%08x_%08x_%08x_%08x\n", u32p[8 * i + 7], u32p[8 * i + 6],
u32p[8 * i + 5], u32p[8 * i + 4], u32p[8 * i + 3], u32p[8 * i + 2], u32p[8 * i + 1],
u32p[8 * i]);
}
}
// print <count> 128-bit numbers from buf
void print128(FILE *f, void *buf, int count) {
uint32_t *u32p = (uint32_t *)buf;
for (int i = 0; i < count; ++i)
fprintf(f, "0x%08x_%08x_%08x_%08x\n", u32p[4 * i + 3], u32p[4 * i + 2], u32p[4 * i + 1],
u32p[4 * i]);
}
ssize_t MicronDmaInputFilter::runMicronDAQ(char **buffer, size_t bufferSize) {
// Usually Pico streams come in two flavors: 4Byte wide, 16Byte wide
// (equivalent to 32bit, 128bit respectively) However, all calls to ReadStream
// and WriteStream must be 16Byte aligned (even for 4B wide streams) There is
// also an 'undocumented' 32Byte wide (256 bit) stream We are using that
// stream here (and in the firmware)
//
// Now allocate 32B aligned space for read and write stream buffers
//
// Similarily, the size of the call, in bytes, must also be a multiple of
// 16Bytes.
//
// err = posix_memalign((void**)&rbuf, 32, size);
//
// NOTE: Buffer are already preallocated and aligned to 32 bytes boundaries
// As with WriteStream, a ReadStream will block until all data is returned
// from the FPGA to the host.
//
// A user application will either have a deterministic amount of results, or a
// non-deterministic amount.
// - When a non-deterministic amount of results are expected, and given the
// blocking nature of the ReadStream,
// a user should use the GetBytesAvailable() call to determine the amount of
// data available for retrieval.
// - When a deterministic amount of results is expected, a user can skip the
// performance impacting
// GetBytesAvailable() call and request the full amount of results. The user
// could also call ReadStream() iteratively, without GetBytesAvailable(), in
// which case getting smaller chunks of results may allow additional
// processing of the data on the host while the FPGA generates more results.
// Either approach works, and should be kept in mind when tuning performance
// of your application.
//
//
// By calling GetBytesAvailable, one can see how much data is ready to read //
// not used for speed
// i = pico->GetBytesAvailable(stream1_, true /* reading */);
// if (i < 0){
// fprintf(stderr, "%s: GetBytesAvailable error: %s\n", "bitfile",
// PicoErrors_FullError(i, ibuf, sizeof(ibuf))); exit(-1);
// }
// Here is where we actually call ReadStream
// This reads "size" number of bytes of data from the output stream specified
// by our stream handle (e.g. 'stream') into our host buffer (rbuf) This call
// will block until it is able to read the entire "size" Bytes of data.
uint32_t *u32p;
uint32_t packetSize;
int err;
bool bril = true;
if (processorType_ == StreamProcessor::ProcessorType::BRIL) {
u32p = (uint32_t *)((*buffer));
packetSize = 20 * 32 * 1791; // bril packet size 16*3488 + 32*8;
} else {
packetSize = 32 * (*((uint32_t *)((*buffer) + 8)) + 2);
}
err = micron_read_stream(pico_, stream2_, *buffer, packetSize);
if (err < 0) {
std::cout << "err = " << err << std::endl;
throw std::runtime_error("ReadStream finished with error");
}
return (packetSize);
}
void MicronDmaInputFilter::rwRegisters() {
// err = micron_WriteDeviceAbsolute(pico_, 8, 0, 32);
// u32p = (uint32_t*) ((*buffer));
// err = micron_ReadDeviceAbsolute(pico_, 4, *buffer, 4);
// std::cout << "reading blocked_ro count " << std::hex << *u32p << std::endl;
/*if (err < 0) {
std::cout << "err = " << err << std::endl;
throw std::runtime_error( "ReadDeviceAbsolute finished with error" );
}
*/
}
/**************************************************************************
* Entry points are here
* Overriding virtual functions
*/
// Print some additional info
void MicronDmaInputFilter::print(std::ostream &out) const {
// out
// << ", DMA errors " << stats.nbDmaErrors
// << ", oversized " << stats.nbDmaOversizedPackets
// << ", resets " << stats.nbBoardResets;
}
// Read a packet from DMA
ssize_t MicronDmaInputFilter::readInput(char **buffer, size_t bufferSize) {
return runMicronDAQ(buffer, bufferSize);
}
#ifndef MICRONDMA_INPUT_FILER_H
#define MICRONDMA_INPUT_FILER_H
#include <memory>
#include "InputFilter.h"
#include "config.h"
#include "libmicron/micron_dma.h"
#include "processor.h"
class MicronDmaInputFilter : public InputFilter {
public:
static bool firstRead;
MicronDmaInputFilter(size_t, size_t, ctrl &, config &);
virtual ~MicronDmaInputFilter();
protected:
ssize_t readInput(char **buffer, size_t bufferSize); // Override
void print(std::ostream &out) const; // Override
private:
micron_private *pico_;
int stream2_;
void rwRegisters();
ssize_t runMicronDAQ(char **buffer, size_t bufferSize);
StreamProcessor::ProcessorType processorType_;
};
typedef std::shared_ptr<MicronDmaInputFilter> MicronDmaInputFilterPtr;
#endif // MICRONDMA_INPUT_FILER_H
#ifndef BRIL_HISTO_H
#define BRIL_HISTO_H
#include <atomic>
#include <fstream>
#include <iostream>
#include <mutex>
#include <queue>
#include <utility>
#include <vector>
#include "controls.h"
#include "tbb/pipeline.h"
template <typename T>
class BrilHistoQueue {
public:
void push(const T &value) {
std::lock_guard<std::mutex> lock(m_mutex);
m_queque.push(value);
}
void pop() {
std::lock_guard<std::mutex> lock(m_mutex);
m_queque.pop();
}
private:
std::queue<T> m_queque;
mutable std::mutex m_mutex;
};
#endif
......@@ -12,7 +12,7 @@
class config {
public:
enum class InputType { WZDMA, DMA, FILEDMA, FILE };
enum class InputType { WZDMA, DMA, FILEDMA, MICRONDMA, FILE };
config(std::string filename);
......@@ -29,6 +29,9 @@ class config {
if (input == "filedma") {
return InputType::FILEDMA;
}
if (input == "micronDMA") {
return InputType::MICRONDMA;
}
if (input == "file") {
return InputType::FILE;
}
......@@ -58,6 +61,8 @@ class config {
return boost::lexical_cast<uint32_t>(v.c_str());
}
const std::string &getBitFileName() const { return vmap.at("bitFileName"); }
StreamProcessor::ProcessorType getProcessorType() const {
const std::string &input = vmap.at("processor_type");
if (input == "PASS_THROUGH") {
......@@ -69,6 +74,9 @@ class config {
if (input == "CALO") {
return StreamProcessor::ProcessorType::CALO;
}
if (input == "BRIL") {
return StreamProcessor::ProcessorType::BRIL;
}
throw std::invalid_argument("Configuration error: Wrong processor type '" + input + "'");
}
......@@ -81,6 +89,9 @@ class config {
bool getOutputForceWrite() const {
return (true ? vmap.at("output_force_write") == "yes" : false);
}
bool getLoadBitFile() const { return (true ? vmap.at("loadBitFile") == "yes" : false); }
uint32_t getNOrbitsPerDMAPacket() const {
std::string v = vmap.at("NOrbitsPerDMAPacket");
return boost::lexical_cast<uint32_t>(v.c_str());
......
......@@ -3,6 +3,7 @@
#include <stdint.h>
#include <atomic>
#include <string>
struct ctrl {
uint32_t run_number;
......
......@@ -29,6 +29,12 @@ struct blockMuon {
uint32_t mu2s[8];
};
struct brilFrame {
uint32_t word;
uint32_t counter;
uint32_t emptyLinks[6];
};
struct bx_map_frame {
uint32_t bx_map_l[8];
};
......@@ -239,6 +245,9 @@ struct constants {
// dma_trailer_size
static constexpr uint32_t intermediate = 0x00000001;
static constexpr uint32_t final = 0x00000001;
static constexpr uint32_t bril_header = 4278781695;
static constexpr uint32_t NBXPerOrbit = 3564;
static constexpr uint32_t NFramesInHistoHeader = 9;
};
#endif
File added
File added
#
# Simple workaround creating a Micron library
#
# exit when any command fails
set -e
rm -f *.o *.a
echo "Compilling..."
g++ -Wl,--copy-dt-needed-entries -std=c++11 -fPIC -Wall -Wextra -g -rdynamic -Wno-multichar -DLINUX -DPOSIX \
-fmessage-length=0 -fdiagnostics-show-option -fms-extensions -Wno-write-strings -DOSNAME=“Linux” \
-I. -I${PICOBASE}/software/include/linux -I${PICOBASE}/software/include \
-c \
${PICOBASE}/software/source/pico_drv_linux.cpp \
${PICOBASE}/software/source/GString.cpp \
${PICOBASE}/software/source/pico_drv.cpp \
${PICOBASE}/software/source/pico_errors.cpp \
${PICOBASE}/software/source/linux/linux.cpp \
${PICOBASE}/software/source/pico_drv_swsim.cpp \
micron_dma.c
echo "Creating library..."
ar rcs libmicron.a GString.o linux.o pico_drv.o pico_drv_linux.o pico_drv_swsim.o pico_errors.o micron_dma.o
/*
* Library encapsulating Micron functions
*/
#include <picodrv.h>
#include <pico_errors.h>
#include "micron_dma.h"
int micron_run_bit_file(const char *bitFilePath, micron_private** micron)
{
//PicoDrv **drvpp
return RunBitFile(bitFilePath, (PicoDrv**) micron);
}
int micron_find_pico(uint32_t model, micron_private** micron)
{
return FindPico(model, (PicoDrv**) micron);
}
int micron_create_stream(micron_private* micron, int streamNum)
{
return ((PicoDrv*) micron)->CreateStream(streamNum);
}
void micron_close_stream(micron_private* micron, int streamHandle)
{
((PicoDrv*) micron)->CloseStream(streamHandle);
}
int micron_read_stream(micron_private* micron, int streamHandle, void *buf, int size)
{
return ((PicoDrv*) micron)->ReadStream(streamHandle, buf, size);
}
int micron_ReadDeviceAbsolute (micron_private* micron, int addr, void* buf, int numBytes)
{
return ((PicoDrv*) micron)->ReadDeviceAbsolute(addr, buf, numBytes);
}
int micron_WriteDeviceAbsolute (micron_private* micron, int addr, void* buf, int numBytes)
{
return ((PicoDrv*) micron)->WriteDeviceAbsolute(addr, buf, numBytes);
}
const char *micron_picoerrors_fullerror(int erC, char *resultP, int resultSize)
{
return PicoErrors_FullError(erC, resultP, resultSize);
}
#ifndef MICRON_DMA_H
#define MICRON_DMA_H
typedef void micron_private;
int micron_run_bit_file(const char *bitFilePath, micron_private **micron);
int micron_find_pico(uint32_t model, micron_private **micron);
int micron_ReadDeviceAbsolute(micron_private *micron, int addr, void *buf, int numBytes);
int micron_WriteDeviceAbsolute(micron_private *micron, int addr, void *buf, int numBytes);
int micron_create_stream(micron_private *micron, int streamNum);
void micron_close_stream(micron_private *micron, int streamHandle);
int micron_read_stream(micron_private *micron, int streamHandle, void *buf, int size);
const char *micron_picoerrors_fullerror(int erC, char *resultP, int resultSize);
#endif // MICRON_DMA_H
......@@ -24,6 +24,9 @@ StreamProcessor::StreamProcessor(size_t max_size_, bool doZS_, ProcessorType pro
myfile.open("example.txt");
}
BrilHistoQueue<std::array<uint32_t, constants::NBXPerOrbit + constants::NFramesInHistoHeader>>
StreamProcessor::BrilQueue;
// Loops over each word in the orbit trailer BX map and fills a vector with the
// non-empty BX values
void bit_check(std::vector<unsigned int> *bx_vect, uint32_t word, uint32_t offset) {
......@@ -109,16 +112,16 @@ StreamProcessor::fillOrbitMetadata StreamProcessor::FillOrbitCalo(
break;
} // orbit trailer has been reached, end of orbit data
uint32_t bx = uint32_t{bx_vect[relbx]};
uint32_t orbit = uint32_t{orbit_header.first};
uint32_t orbit_ = uint32_t{orbit_header.first};
if (bx > 3554) {
orbit--;
orbit_--;
} // fix for the fact that bx 3555 - 3564 are from the previous orbit
uint32_t header = uint32_t{orbit_header.second}; // header can be added to later
memcpy(wr_ptr, (char *)&header, 4);
wr_ptr += 4;
memcpy(wr_ptr, (char *)&bx, 4);
wr_ptr += 4;
memcpy(wr_ptr, (char *)&orbit, 4);
memcpy(wr_ptr, (char *)&orbit_, 4);
wr_ptr += 4;
for (uint32_t i = 0; i < 8; i++) {
memcpy(wr_ptr, (char *)&i, 4);
......@@ -148,6 +151,57 @@ StreamProcessor::fillOrbitMetadata StreamProcessor::FillOrbitCalo(
return meta;
}
uint32_t StreamProcessor::FillBril(char *rd_ptr, char *wr_ptr, char *end_ptr) {
static constexpr uint32_t NHistosPerPacket = 20; // should not be changed, any more and SB852
// crashes, would need to re-upload bitfile
uint32_t histo_i, histo_word_i = 0;
std::array<std::array<uint32_t, constants::NBXPerOrbit + constants::NFramesInHistoHeader>,
NHistosPerPacket>
histo_arr;
// uint32_t histo_arr[NHistosPerPacket][constants::NBXPerOrbit +
// NFramesInHistoHeader];
// BrilHistoQueue<std::array<uint32_t, constants::NBXPerOrbit +
// constants::NFramesInHistoHeader>> BrilQueue;
while ((rd_ptr != end_ptr) && (histo_i < NHistosPerPacket)) {
brilFrame *fr = reinterpret_cast<brilFrame *>(rd_ptr);
if (fr->word == constants::bril_header) {
rd_ptr += 32;
histo_i++;
histo_word_i = 0;
continue;
}
if (histo_i == 0) {
continue;
} // Currently appears to be a bug where first histogram of packet is
// truncated, need to understand and fix, for now skip
if (histo_word_i < constants::NFramesInHistoHeader) {
histo_arr[histo_i][histo_word_i] = (fr->word >> 0) & 0xffffffff;
} else {
histo_arr[histo_i][(histo_word_i * 2) - constants::NFramesInHistoHeader] =
(fr->word >> 0) & 0xffff;
histo_arr[histo_i][(histo_word_i * 2) + 1 - constants::NFramesInHistoHeader] =
(fr->word >> 16) & 0xffff;
}
rd_ptr += sizeof(brilFrame);
histo_word_i++;
}
uint32_t packed_size = sizeof(uint32_t) * NHistosPerPacket *
(constants::NBXPerOrbit + constants::NFramesInHistoHeader);
memcpy(wr_ptr, (char *)&histo_arr, packed_size);
wr_ptr += packed_size;
for (std::array<uint32_t, constants::NBXPerOrbit + constants::NFramesInHistoHeader> &hist :
histo_arr) {
BrilQueue.push(hist);
}
return packed_size;
}
// Goes through orbit worth of data and fills the output memory with the muons
// corresponding to the non-empty bunchcrossings, as marked in bx_vect
StreamProcessor::fillOrbitMetadata StreamProcessor::FillOrbitMuon(
......@@ -267,6 +321,7 @@ void StreamProcessor::process(Slice &input, Slice &out) {
char *rd_ptr = input.begin();
char *wr_ptr = out.begin();
char *end_ptr = input.end();
uint32_t counts = 0;
bool endofpacket = false;
uint32_t orbit_per_packet_count = 0;
......@@ -280,6 +335,12 @@ void StreamProcessor::process(Slice &input, Slice &out) {
out.set_counts(1);
return;
}
if (processorType == ProcessorType::BRIL) {
counts = FillBril(rd_ptr, wr_ptr, end_ptr);
out.set_end(out.begin() + counts);
out.set_counts(counts);
return;
}
if (!CheckFrameMultBlock(input.size())) {
return;
......
......@@ -7,16 +7,21 @@
#include <utility>
#include <vector>
#include "bril_histo.h"
#include "controls.h"
#include "format.h"
#include "tbb/pipeline.h"
// reformatter
class Slice;
class StreamProcessor : public tbb::filter {
public:
enum class ProcessorType { PASS_THROUGH, GMT, CALO };
static BrilHistoQueue<
std::array<uint32_t, constants::NBXPerOrbit + constants::NFramesInHistoHeader>>
BrilQueue;
enum class ProcessorType { PASS_THROUGH, GMT, CALO, BRIL };
StreamProcessor(size_t max_size_, bool doZS_, ProcessorType processorType_,
uint32_t nOrbitsPerDMAPacket_, uint32_t prescaleFactor, ctrl &control);
void *operator()(void *item) /*override*/;
......@@ -33,6 +38,7 @@ class StreamProcessor : public tbb::filter {
inline std::pair<uint32_t, bool> ProcessOrbitHeader(char *rd_ptr);
fillOrbitMetadata FillOrbitMuon(std::vector<unsigned int> &bx_vect, char *rd_ptr, char *wr_ptr);
fillOrbitMetadata FillOrbitCalo(std::vector<unsigned int> &bx_vect, char *rd_ptr, char *wr_ptr);
uint32_t FillBril(char *rd_ptr, char *wr_ptr, char *end_ptr);
std::ofstream myfile;
size_t max_size;
uint64_t nbPackets;
......
TARGET = flash_ctl
USER_SOURCES = flash_ctl.cpp i2c.cpp
include $(PICOBASE)/software/Makefile.common
File added
This diff is collapsed.
/*===================================================================================
File: i2c.cpp.
This module contains utilities designed to communicate with the I2C port on pico
boards such as teh SB-852.
A stream connects to a 64-bit PicoBus that is used to read and write registers in
the I2C master which can then read and write registers in a slave I2C device such
as the CPLD on the SB-852.
The software sequence for an I2C access is:
Write:
Poll I2C_CONFIG_REG, bit[31] will be 1 while the I2C cycle is in progress, 0 when done
Write I2C_WRDATA_REG with WriteData[31:0] // Dont care for reads
Write I2C_ADDR_REG with the I2C Register Address[31:0] being accessed
Write I2C_CONFIG_REG[23:0] with {data_byte_count[7:0], adr_byte_count[7:0], I2C_Device_Addr[6:0], R/Wn}
Read:
Poll I2C_CONFIG_REG, bit[31] will be 1 while the I2C cycle is in progress, 0 when done
Write I2C_ADDR_REG with the I2C Register Address[31:0] being accessed
Write I2C_CONFIG_REG[23:0] with {data_byte_count[7:0], adr_byte_count[7:0], I2C_Device_Addr[6:0], R/Wn}
Poll I2C_CONFIG_REG, bit[31] will be 1 while the I2C cycle is in progress, 0 when done
Read I2C_RDDATA_REG for the read data, on read cycles only
=====================================================================================*/
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <time.h>
#include <getopt.h>
#include <picodrv.h>
#include <pico_errors.h>
#include "i2c.h"
// Globals
extern PicoDrv *pico;
extern int streamhandle;
extern uint32_t *readbuf, *writebuf;
extern int verbose;
// Routine to poll the I2C controller cycle in progress bit until it is deasserted
void check_i2c_busy() {
int err;
char ibuf[1024];
writebuf[0] = 0x8; // Data length in bytes of stream command
writebuf[1] = I2C_CONFIG_REG; // Register Address
writebuf[2] = 0x1; // Read cmd, bit[64]=1
writebuf[3] = 0x0; // unused
if (verbose) {
printf("Checking I2C busy");
}
do {
err = pico->WriteStream(streamhandle, &writebuf[0], 16);
if (err < 0) {
fprintf(stderr, "check_i2c_busy: WriteStream error: %s\n", PicoErrors_FullError(err, ibuf, sizeof(ibuf)));
exit(-1);
}
err = pico->ReadStream(streamhandle, readbuf, 16);
if (err < 0) {
fprintf(stderr, "check_i2c_busy: ReadStream error: %s\n", PicoErrors_FullError(err, ibuf, sizeof(ibuf)));
exit(-1);
}
if (verbose) {
printf("Register %04X = %08X\n", I2C_CONFIG_REG, readbuf[0]);
}
} while ((readbuf[0] & 0x80000000) == 0x80000000); // loop until I2C cycle in progress bit is low
}
// I2C write cycle. Device Address is 7-bits. Register Address is 0 to 4 bytes. Write data is 1 to 4 bytes.
void i2c_write(uint32_t dev_addr, uint32_t reg_addr, uint32_t addr_bytes, uint32_t wrdata, uint32_t data_bytes) {
int err;
char ibuf[1024];
check_i2c_busy();
// Write the I2C wrdata to the I2C_WRDATA_REG of the I2C controller through the stream interface
writebuf[0] = 0x8; // Data length in bytes of PicoBus cycle
writebuf[1] = I2C_WRDATA_REG; // Picobus Address
writebuf[2] = 0x0; // Write cmd, bit[64] = 0
writebuf[3] = 0x0; // unused upper portion of stream command word
writebuf[4] = wrdata; // lower 32-bits of the PicoBus 64-bit data contains the I2C write data
writebuf[5] = 0; // high 32-bits of the PicoBus 64-bit data, unused
writebuf[6] = 0x0; // unused upper portion of stream data word
writebuf[7] = 0x0; // unused upper portion of stream data word
if (verbose) printf("Writing %08X to %08X \n", writebuf[1], writebuf[4]);
err = pico->WriteStream(streamhandle, &writebuf[0], 32); // Stream write of 32 bytes, two 128-bit words
if (err < 0) {
fprintf(stderr, "i2c_write: WriteStream error: %s\n", PicoErrors_FullError(err, ibuf, sizeof(ibuf)));
exit(-1);
}
// Write the I2C register address to the I2C_ADDR_REG of the I2C controller through the stream interface
writebuf[0] = 0x8; // Data length in bytes of PicoBus cycle
writebuf[1] = I2C_ADDR_REG; // Picobus Address
writebuf[2] = 0x0; // Write cmd, bit[64] = 0
writebuf[3] = 0x0; // unused upper portion of stream command word
writebuf[4] = reg_addr; // lower 32-bits of the PicoBus 64-bit data contains the I2C register address
writebuf[5] = 0; // high 32-bits of the PicoBus 64-bit data, unused
writebuf[6] = 0x0; // unused upper portion of stream data word
writebuf[7] = 0x0; // unused upper portion of stream data word
if (verbose) printf("Writing %08X to %08X \n", writebuf[1], writebuf[4]);
err = pico->WriteStream(streamhandle, &writebuf[0], 32); // Stream write of 32 bytes, two 128-bit words
if (err < 0) {
fprintf(stderr, "i2c_write: WriteStream error: %s\n", PicoErrors_FullError(err, ibuf, sizeof(ibuf)));
exit(-1);
}
// Write the I2C device address, num address bytes and num data bytes to the I2C_CONFIG_REG of the I2C controller through the stream interface
writebuf[0] = 0x8; // Data length in bytes of PicoBus cycle
writebuf[1] = I2C_CONFIG_REG; // Picobus Address
writebuf[2] = 0x0; // Write cmd, bit[64] = 0
writebuf[3] = 0x0; // unused upper portion of stream command word
// lower 32-bits of the PicoBus 64-bit data contains {data_byte_count[7:0], adr_byte_count[7:0], I2C_Device_Addr[6:0], R/Wn}
writebuf[4] = ((data_bytes & 0xFF)<<16) | ((addr_bytes & 0xFF)<<8) | ((dev_addr & 0xFF)<<1) | 0x00; // R/Wn=0
writebuf[5] = 0; // high 32-bits of the PicoBus 64-bit data, unused
writebuf[6] = 0x0; // unused upper portion of stream data word
writebuf[7] = 0x0; // unused upper portion of stream data word
if (verbose) printf("Writing %08X to %08X \n", writebuf[1], writebuf[4]);
err = pico->WriteStream(streamhandle, &writebuf[0], 32); // Stream write of 32 bytes, two 128-bit words
if (err < 0) {
fprintf(stderr, "i2c_write: WriteStream error: %s\n", PicoErrors_FullError(err, ibuf, sizeof(ibuf)));
exit(-1);
}
}
// I2C read cycle. Device Address is 7-bits. Register Address is 0 to 4 bytes. Write data is 1 to 4 bytes.
uint32_t i2c_read(uint32_t dev_addr, uint32_t reg_addr, uint32_t addr_bytes, uint32_t data_bytes) {
int err;
char ibuf[1024];
check_i2c_busy();
// Write the I2C register address to the I2C_ADDR_REG of the I2C controller through the stream interface
writebuf[0] = 0x8; // Data length in bytes of PicoBus cycle
writebuf[1] = I2C_ADDR_REG; // Picobus Address
writebuf[2] = 0x0; // Write cmd, bit[64] = 0
writebuf[3] = 0x0; // unused upper portion of stream command word
writebuf[4] = reg_addr; // lower 32-bits of the PicoBus 64-bit data contains the I2C register address
writebuf[5] = 0; // high 32-bits of the PicoBus 64-bit data, unused
writebuf[6] = 0x0; // unused upper portion of stream data word
writebuf[7] = 0x0; // unused upper portion of stream data word
if (verbose) printf("Writing %08X to %08X \n", writebuf[1], writebuf[4]);
err = pico->WriteStream(streamhandle, &writebuf[0], 32); // Stream write of 32 bytes, two 128-bit words
if (err < 0) {
fprintf(stderr, "i2c_read: WriteStream error: %s\n", PicoErrors_FullError(err, ibuf, sizeof(ibuf)));
exit(-1);
}
// Write the I2C device address, num address bytes and num data bytes to the I2C_CONFIG_REG of the I2C controller through the stream interface
writebuf[0] = 0x8; // Data length in bytes of PicoBus cycle
writebuf[1] = I2C_CONFIG_REG; // Picobus Address
writebuf[2] = 0x0; // Write cmd, bit[64] = 0
writebuf[3] = 0x0; // unused upper portion of stream command word
// lower 32-bits of the PicoBus 64-bit data contains {data_byte_count[7:0], adr_byte_count[7:0], I2C_Device_Addr[6:0], R/Wn}
writebuf[4] = ((data_bytes & 0xFF)<<16) | ((addr_bytes & 0xFF)<<8) | ((dev_addr & 0xFF)<<1) | 0x01; // R/Wn=1
writebuf[5] = 0; // high 32-bits of the PicoBus 64-bit data, unused
writebuf[6] = 0x0; // unused upper portion of stream data word
writebuf[7] = 0x0; // unused upper portion of stream data word
if (verbose) printf("Writing %08X to %08X \n", writebuf[1], writebuf[4]);
err = pico->WriteStream(streamhandle, &writebuf[0], 32); // Stream write of 32 bytes, two 128-bit words
if (err < 0) {
fprintf(stderr, "i2c_read: WriteStream error: %s\n", PicoErrors_FullError(err, ibuf, sizeof(ibuf)));
exit(-1);
}
check_i2c_busy();
// Send I2C controller read data command to the stream interface
writebuf[0] = 0x8; // Data length in bytes of stream command
writebuf[1] = I2C_RDDATA_REG; // Picobus Address
writebuf[2] = 0x1; // Read cmd, bit[64] = 1
writebuf[3] = 0x0; // unused upper portion of stream command word
err = pico->WriteStream(streamhandle, &writebuf[0], 16);
if (err < 0) {
fprintf(stderr, "i2c_read: WriteStream error: %s\n", PicoErrors_FullError(err, ibuf, sizeof(ibuf)));
exit(-1);
}
// clear the read buffer to prepare for the read.
memset(readbuf, 0, sizeof(readbuf));
// Read the response data from the stream interface.
err = pico->ReadStream(streamhandle, readbuf, 16);
if (err < 0) {
fprintf(stderr, "flash_ctl_rd: ReadStream error: %s\n", PicoErrors_FullError(err, ibuf, sizeof(ibuf)));
exit(-1);
}
return (readbuf[0]);
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment