KM3NeT CLB  2.0
KM3NeT CLB v2 Embedded Software
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
octopus.c
1 /*
2  * KM3NeT CLB v2 Firmware
3  * ----------------------
4  *
5  * Copyright 2013 KM3NeT Collaboration
6  *
7  * All Rights Reserved.
8  *
9  *
10  * File : octopus.c
11  * Created : 22 jan. 2014
12  * Author : Vincent van Beveren
13  */
14 
15 
16 #include "modules/octopus.h"
17 
18 #include <assert.h>
19 #include <string.h>
20 
21 #include "errorcode.h"
22 #include "kernel/err.h"
23 #include "kernel/tm.h"
24 #include "lm32soc/dev_soc.h"
25 #include "util/log.h"
26 #include <stdio.h>
27 
28 #include "drv/i2c/pca9548.h"
29 #include "drv/i2c/octocpld.h"
30 #include "drv/i2c/promis.h"
31 
32 
33 
34 LOG_DEF(Octo);
35 
36 typedef struct {
37  I2C_Device * dev;
38  uint8_t cpld;
39  uint8_t muxb;
40  uint8_t chs;
41 } OctoBrdCfg;
42 
43 #define _OCTO_BOARDS 2
44 #define _OCTO_CH_MUX 8
45 #define _OCTO_CHS2MUX(CHS) ( ( CHS + ( _OCTO_CH_MUX - 1 ) ) / _OCTO_CH_MUX )
46 
47 
48 
49 static const OctoBrdCfg _octoBrdCfg[_OCTO_BOARDS] = {
52 };
53 
54 
55 
56 static bool octoSelPMT(const OctoBrdCfg * cfg, int ch, bool * was_on)
57 {
58  uint32_t onChTmp;
59 
60 
61  if (!ocRead(cfg->dev, cfg->cpld, ocRegOn, &onChTmp)) return false;
62 
63  if (onChTmp & BIT(ch)) {
64  *was_on = true;
65  } else {
66  *was_on = false;
67 
68  // if the PMT is not enabled, we enable it temporarily
69  onChTmp |= BIT(ch);
70  if (!ocWrite(cfg->dev, cfg->cpld, ocRegOn, onChTmp)) return false;
71  }
72 
73  // also enable the clock
74  if (!ocWrite(cfg->dev, cfg->cpld, ocRegClkEn, BIT(ch))) return false;
75 
76  // and select the correct channel on the mux.
77  return pca9548_select(cfg->dev, cfg->muxb + (ch / _OCTO_CH_MUX), ch % _OCTO_CH_MUX);
78 }
79 
80 static bool octoDeSelPMT(const OctoBrdCfg * cfg, int ch, bool was_on)
81 {
82  uint32_t onChTmp;
83  // select no channel on the mux.
84  pca9548_select(cfg->dev, cfg->muxb + (ch / _OCTO_CH_MUX), -1);
85  // disable the clock
86  ocWrite(cfg->dev, cfg->cpld, ocRegClkEn, 0);
87 
88  // if its not supposed to be on, switch it off
89  if (!was_on)
90  {
91  if (!ocRead(cfg->dev, cfg->cpld, ocRegOn, &onChTmp)) return false;
92  onChTmp &= ~BIT(ch);
93  if (!ocWrite(cfg->dev, cfg->cpld, ocRegOn, onChTmp)) return false;
94  }
95 
96  return !errHas();
97 }
98 
99 
100 void octoResetBoard(int brd)
101 {
102  const OctoBrdCfg * cfg = &_octoBrdCfg[brd];
103  int i;
104 
105  for (i = 0; i < _OCTO_CHS2MUX(cfg->chs); ++i)
106  {
107  if (!pca9548_select(cfg->dev, cfg->muxb + i, -1)) {
108  logWarn("Could not communicate with MUX %d:%d : %s (%08x)", i, cfg->chs,
109  errGetDescr(), errGet());
110  errClear();
111  }
112  }
113 
114  if (!ocWakeUp(cfg->dev, cfg->cpld)) {
115  logWarn("Failed to wake up CPLD %d: %s (%08x)", cfg->chs,
116  errGetDescr(), errGet());
117  errClear();
118  return;
119  }
120 
121  if (!ocWrite(cfg->dev, cfg->cpld, ocRegClkEn, 0)) {
122  logWarn("Could not communicate with CPLD %d: %s (%08x)", cfg->chs,
123  errGetDescr(), errGet());
124  errClear();
125  }
126  ocWrite(cfg->dev, cfg->cpld, ocRegOn, 0);
127  errClear();
128 }
129 
130 bool octoDeinitChan(int brd, int ch)
131 {
132  uint32_t onChTmp;
133  const OctoBrdCfg * cfg = &_octoBrdCfg[brd];
134  if (!ocRead(cfg->dev, cfg->cpld, ocRegOn, &onChTmp)) return false;
135  onChTmp &= ~BIT(ch);
136  if (!ocWrite(cfg->dev, cfg->cpld, ocRegOn, onChTmp)) return false;
137  return true;
138 }
139 
140 bool octoInitChan(int brd, int ch, uint8_t highVolt, uint8_t threshold)
141 {
142  const OctoBrdCfg * brdCfg = &_octoBrdCfg[brd];
143 
144  bool was_on;
145 
146  if (!octoSelPMT(brdCfg, ch, &was_on)) goto fail;
147 
148  if (!was_on) timeDelay(2);
149 
150  PrmsConfig prmsCfg = {
151  .highVolt = highVolt,
152  .threshold = threshold
153  };
154 
155  if (!prmsSetConfig(brdCfg->dev, OCTO_PROMIS_I2C_ADDR, &prmsCfg)) goto fail;
156  // if (!prmsGetConfig(brdCfg->dev, OCTO_PROMIS_I2C_ADDR, &prmsCfg)) goto fail;
157  //printf("Setting channel %d %d: %02x %02x\n", brd, ch, prmsCfg.highVolt, prmsCfg.threshold);
158 
159 
160  if (!octoDeSelPMT(brdCfg, ch, true)) return false;
161 
162  return true;
163 fail:
164  octoDeSelPMT(brdCfg, ch, was_on);
165  return false;
166 }
167 
168 bool octoPMTID(int brd, int ch, uint32_t * id, bool * pmtIdFault)
169 {
170  const OctoBrdCfg * brdCfg = &_octoBrdCfg[brd];
171 
172  bool was_on;
173  if (pmtIdFault != NULL) *pmtIdFault = false;
174 
175  if (!octoSelPMT(brdCfg, ch, &was_on)) goto fail;
176 
177  uint8_t buf[3];
178 
179  if (!prmsID(brdCfg->dev, OCTO_PROMIS_I2C_ADDR, buf)) {
180 
181  if (errGet() == E_PRMS_ID_FAULT) {
182  if (pmtIdFault != NULL) *pmtIdFault = true;
183  errClear();
184  } else return false;
185  }
186 
187  *id = (buf[0] << 16) | (buf[1] << 8) | buf[2];
188 
189  if (!octoDeSelPMT(brdCfg, ch, was_on)) return false;
190  return true;
191 fail:
192  octoDeSelPMT(brdCfg, ch, was_on);
193  return false;
194 }
195 
196 
197 bool octoPiezo(bool on)
198 {
199  const OctoBrdCfg * cfg = &_octoBrdCfg[OCTO_BRD_LARGE];
200  uint32_t onChTmp;
201  if (!ocRead(cfg->dev, cfg->cpld, ocRegOn, &onChTmp)) return false;
202  if (on) {
203  onChTmp |= BIT(OCTOL_PIEZO);
204  } else {
205  onChTmp &= ~BIT(OCTOL_PIEZO);
206  }
207  return ocWrite(cfg->dev, cfg->cpld, ocRegOn, onChTmp);
208 }
209 
210 bool octoReadFault(int brd, uint32_t * fault)
211 {
212  return ocRead(_octoBrdCfg[brd].dev, _octoBrdCfg[brd].cpld, ocRegFault, fault);
213 }
214 
215 bool octoReadEnabled(int brd, uint32_t * enabled)
216 {
217  return ocRead(_octoBrdCfg[brd].dev, _octoBrdCfg[brd].cpld, ocRegOn, enabled);
218 }
219 
220 
221 bool octoHighVoltage(int brd, int ch, bool hvOn)
222 {
223  const OctoBrdCfg * cfg = &_octoBrdCfg[brd];
224  bool was_on;
225 
226  if (!octoSelPMT(cfg, ch, &was_on)) goto fail;
227 
228  if (!was_on) timeDelay(2);
229 
230  if (!prmsHighVolt(cfg->dev, OCTO_PROMIS_I2C_ADDR, hvOn)) goto fail;
231 
232  return octoDeSelPMT(cfg, ch, was_on);
233 fail:
234  octoDeSelPMT(cfg, ch, was_on);
235  return false;
236 }
237 
238 bool octoChainTest(int brd, int ch)
239 {
240 
241  const OctoBrdCfg * cfg = &_octoBrdCfg[brd];
242  bool was_on;
243  if (!octoSelPMT(cfg, ch, &was_on)) goto fail;
244 
245  if (!was_on) timeDelay(2);
246 
247  if (!prmsChainTest(cfg->dev, OCTO_PROMIS_I2C_ADDR)) goto fail;
248 
249  return octoDeSelPMT(cfg, ch, was_on);
250 fail:
251  octoDeSelPMT(cfg, ch, was_on);
252  return false;
253 }
254 
bool errHas()
Returns whether there is an error pending.
Definition: err.c:52
This module implements the functionality required by the octopus board (large).
bool octoHighVoltage(int brd, int ch, bool hvOn)
Turns the high-voltage on or off.
Definition: octopus.c:221
#define OCTOS_MUXB_I2C_ADDR
Octopus small I2C MUX base address.
Definition: cfg_board.h:106
Configuration struct.
Definition: promis.h:82
#define OCTOS_CPLD_I2C_ADDR
Octopus small CLPD address.
Definition: cfg_board.h:102
bool octoPiezo(bool on)
Turns the Piezo on or off.
Definition: octopus.c:197
#define OCTOL_CPLD_I2C_ADDR
Octopus large CLPD base address.
Definition: cfg_board.h:91
bool prmsChainTest(I2C_Device *dev, uint8_t addr)
Executes a chain test.
Definition: promis.c:90
Fault register.
Definition: octocpld.h:39
#define BIT(N)
Makes a value with the specified bit set.
Definition: macro.h:108
bool octoChainTest(int brd, int ch)
Executes a chain-test.
Definition: octopus.c:238
#define OCTOS_I2C_DEV
Octopus small I2C device.
Definition: cfg_board.h:100
Structure defines OpenCores I2C Device.
Definition: dev_i2c.h:55
#define E_PRMS_ID_FAULT
PROMiS ID is not consistent.
Definition: promis.h:34
#define OCTOL_I2C_DEV
Octopus large I2C device.
Definition: cfg_board.h:89
const char * errGetDescr()
Returns the last error description, if any, else null.
Definition: err.c:57
bool prmsID(I2C_Device *dev, uint8_t addr, uint8_t *id)
Returns the burned ID of the PROMiS device.
Definition: promis.c:41
void octoResetBoard(int brd)
Definition: octopus.c:100
void timeDelay(uint32_t msec)
Simple busy-wait delay.
Definition: tm.c:18
bool octoInitChan(int brd, int ch, uint8_t highVolt, uint8_t threshold)
Initializes a channel on the octopus board.
Definition: octopus.c:140
bool octoPMTID(int brd, int ch, uint32_t *id, bool *pmtIdFault)
Reads a PMT ID.
Definition: octopus.c:168
Clock enable.
Definition: octocpld.h:40
#define logWarn(MSG,...)
Format a log message with warning level.
Definition: log.h:219
#define OCTOL_MUXB_I2C_ADDR
Octopus large I2C MUX base address.
Definition: cfg_board.h:95
PCA9548 I2C mux driver.
#define OCTOS_PMT_CH
Octopus small PMT channel count.
Definition: cfg_board.h:104
#define OCTO_BRD_LARGE
Octo large.
Definition: octopus.h:40
PMT On register.
Definition: octocpld.h:38
Manages the global system error.
Simple timer functions.
bool ocWrite(I2C_Device *dev, uint8_t addr, OCReg reg, uint32_t value)
Writes one of the CPLD registers.
Definition: octocpld.c:31
void errClear()
Clears the current error.
Definition: err.c:46
bool octoDeinitChan(int brd, int ch)
De-Initializes a channel on the octopus board.
Definition: octopus.c:130
uint32_t errGet()
Returns the last error code, or null.
Definition: err.c:74
This module is responsible for distributing error codes.
#define LOG_DEF(NAME,...)
Define a logger for a module.
Definition: log.h:129
#define OCTOL_PMT_CH
Octopus large PMT channel count.
Definition: cfg_board.h:93
bool octoReadFault(int brd, uint32_t *fault)
Reads the fault register of the CLPD.
Definition: octopus.c:210
#define OCTO_PROMIS_I2C_ADDR
Generic PROMiS I2C address.
Definition: cfg_board.h:109
bool ocRead(I2C_Device *dev, uint8_t addr, OCReg reg, uint32_t *value)
Reads one of the CPLD registers.
Definition: octocpld.c:18
bool prmsSetConfig(I2C_Device *dev, uint8_t addr, PrmsConfig *cfg)
Sets the configuration on the PROMiS device.
Definition: promis.c:68
uint8_t highVolt
high voltage DAC value
Definition: promis.h:84
static bool pca9548_select(I2C_Device *dev, int addr, int ch)
Select a specific channel on the PCA9548.
Definition: pca9548.h:40
This driver interfaces with the PROMiS PMT ASIC.
This driver encapsulates the functionality of the CPLD on the octopus board.
This file assigns all device structures to memory mapped structures.
bool prmsHighVolt(I2C_Device *dev, uint8_t addr, bool enable)
Enables/Disables the high voltage.
Definition: promis.c:85
#define OCTOL_PIEZO
Position of the Piezo.
Definition: cfg_board.h:97
Implements a generic logger facility.
static bool ocWakeUp(I2C_Device *dev, uint8_t addr)
Wakes up the octopus board, apparently it needs it.
Definition: octocpld.h:76