REDAC HybridController
Firmware for LUCIDAC/REDAC Teensy
Loading...
Searching...
No Matches
functions.cpp
Go to the documentation of this file.
1// Copyright (c) 2024 anabrid GmbH
2// Contact: https://www.anabrid.com/licensing/
3// SPDX-License-Identifier: MIT OR GPL-2.0-or-later
4
5#include <bus/functions.h>
6
7functions::Function::Function(const bus::addr_t address) : address(address) {}
8
10 bus::address_function(address);
11 bus::activate_address();
12 delayNanoseconds(2 * 42);
13 bus::deactivate_address();
14}
15
16functions::DataFunction::DataFunction(bus::addr_t address, const SPISettings &spiSettings)
17 : Function(address), spi_settings(spiSettings) {}
18
20 /*
21 * HACK: Do two-step addressing to circumvent hardware limitations,
22 * see lucidac/hardware/dimm-template-rev1/-/issues/2
23 *
24 * For each block, we have to define an unused (or practically no-op) address that
25 * gets addressed first to assert the correct MSELECT signal, before we address
26 * the actual address. Otherwise, the SPI mode can not be correctly set.
27 * Each block requires different addresses. See the issue for background info.
28 */
29 auto block_address = bus::remove_addr_parts(address, false, true);
30 auto hack_msel_only_address = address;
31
32 switch (block_address) {
33 case 0:
34 break;
35 case /* 1 */ bus::CTRL_BLOCK_BADDR:
36 hack_msel_only_address = 5;
37 break;
38 case /* 2 */ bus::BACKPLANE_BADDR:
39 // This is actually the "front plane" for LUCIDAC (with analog in/outs, function generator, ...)
40 // On LUCIDAC front plane, CS={1,7} are free
41 // This is the "back plane" for REDAC (with T-Blocks, backplane identification, ...)
42 // On REDAC back plane, CS=3 is free
43 // TODO: Introduce some mechanism to differentiate between LUCIDAC and REDAC here.
44 // For now, just have it separate on the two branches.
45 hack_msel_only_address = 1;
46 break;
47 case /* 3 */ bus::AUX_BADDR:
48 // This is actually non-existent for the LUCIDAC
49 // This is not yet existent for the REDAC
50 break;
51 case /* 4 */ bus::T_BLOCK_BADDR:
52 hack_msel_only_address = bus::replace_function_idx(address, 7);
53 break;
54 case /* 5 */ bus::CARRIER_BADDR:
55 hack_msel_only_address = bus::replace_function_idx(address, 15);
56 break;
57 case /* 6 */ bus::REDAC_BACKPLANE_SIGNAL_PROCESSING_BADDR:
58 case /* 7 */ bus::RESERVED_BADDR:
59 // Both currently not used
60 break;
61 case /* 8 */ bus::U_BLOCK_BADDR(0):
62 case /* 16 */ bus::U_BLOCK_BADDR(1):
63 case /* 24 */ bus::U_BLOCK_BADDR(2):
64 if (bus::get_function_idx(address) == 2)
65 hack_msel_only_address = bus::replace_function_idx(address, 3);
66 else
67 hack_msel_only_address = bus::replace_function_idx(address, 2);
68 break;
69 case /* 9 */ bus::C_BLOCK_BADDR(0):
70 case /* 17 */ bus::C_BLOCK_BADDR(1):
71 case /* 25 */ bus::C_BLOCK_BADDR(2):
72 hack_msel_only_address = bus::replace_function_idx(address, 48);
73 break;
74 case /* 10 */ bus::I_BLOCK_BADDR(0):
75 case /* 18 */ bus::I_BLOCK_BADDR(1):
76 case /* 26 */ bus::I_BLOCK_BADDR(2):
77 if (bus::get_function_idx(address) == 5)
78 hack_msel_only_address = bus::replace_function_idx(address, 6);
79 else
80 hack_msel_only_address = bus::replace_function_idx(address, 5);
81 break;
82 case /* 11 */ bus::SH_BLOCK_BADDR(0):
83 case /* 19 */ bus::SH_BLOCK_BADDR(1):
84 case /* 27 */ bus::SH_BLOCK_BADDR(2):
85 hack_msel_only_address = bus::replace_function_idx(address, 8);
86 break;
87 case /* 12 */ bus::M0_BLOCK_BADDR(0):
88 case /* 20 */ bus::M0_BLOCK_BADDR(1):
89 case /* 28 */ bus::M0_BLOCK_BADDR(2):
90 case /* 13 */ bus::M1_BLOCK_BADDR(0):
91 case /* 21 */ bus::M1_BLOCK_BADDR(1):
92 case /* 29 */ bus::M1_BLOCK_BADDR(2):
93 // CS = 15 should be free for both, but does not work
94 hack_msel_only_address = bus::replace_function_idx(address, 2);
95 break;
96 case /* 14 */ bus::REDAC_ADC_PSEUDO_BLOCK_BADDR(0):
97 case /* 22 */ bus::REDAC_ADC_PSEUDO_BLOCK_BADDR(1):
98 case /* 30 */ bus::REDAC_ADC_PSEUDO_BLOCK_BADDR(2):
99 hack_msel_only_address = bus::replace_function_idx(address, 4);
100 break;
101 case /* 15 */ bus::REDAC_BACKPLANE_T0_BLOCK_BADDR:
102 case /* 23 */ bus::REDAC_BACKPLANE_T1_BLOCK_BADDR:
103 case /* 31 */ bus::REDAC_BACKPLANE_TAUX_BLOCK_BADDR:
104 // Must possibly be adapted when T-blocks on backplane are changed
105 hack_msel_only_address = bus::replace_function_idx(address, 7);
106 break;
107 }
108
109 bus::address_function(hack_msel_only_address);
110 bus::activate_address();
111 bus::address_function(address);
112 bus::spi.beginTransaction(spi_settings);
113 delayNanoseconds(200);
114 bus::activate_address();
115}
116
118 bus::deactivate_address();
119 bus::spi.endTransaction();
120}
121
122void functions::DataFunction::transfer(const void *mosi_buf, void *miso_buf, size_t count) const {
123 begin_communication();
124 bus::spi.transfer(mosi_buf, miso_buf, count);
125 end_communication();
126}
127
128uint8_t functions::DataFunction::transfer8(uint8_t data_in) const {
129 begin_communication();
130 auto ret = bus::spi.transfer(data_in);
131 end_communication();
132 return ret;
133}
134
135uint16_t functions::DataFunction::transfer16(uint16_t data_in) const {
136 begin_communication();
137 auto ret = bus::spi.transfer16(data_in);
138 end_communication();
139 return ret;
140}
141
143 begin_communication();
144 auto ret = bus::spi.transfer32(data_in);
145 end_communication();
146 return ret;
147}
148
void end_communication() const
static SPIClass & get_raw_spi()
uint16_t transfer16(uint16_t data_in) const
uint8_t transfer8(uint8_t data_in) const
void begin_communication() const
Definition functions.cpp:19
DataFunction(bus::addr_t address, const SPISettings &spiSettings)
Definition functions.cpp:16
void transfer(const void *mosi_buf, void *miso_buf, size_t count) const
uint32_t transfer32(uint32_t data_in) const
Function classes encapsulate digital bus calls.
Definition functions.h:21
Function(bus::addr_t address)
Definition functions.cpp:7
uint32_t
Definition flasher.cpp:195
if(((src) >=(0x60000000) &&(src)<(0x60000000)+(0x800000)))
Definition flasher.cpp:177
Definition bus.h:21
SPIClass & spi
Definition bus.cpp:10