CuVoodoo STM32F1 firmware template
microwire_master.c
Go to the documentation of this file.
1 /* This program is free software: you can redistribute it and/or modify
2  * it under the terms of the GNU General Public License as published by
3  * the Free Software Foundation, either version 3 of the License, or
4  * (at your option) any later version.
5  *
6  * This program is distributed in the hope that it will be useful,
7  * but WITHOUT ANY WARRANTY; without even the implied warranty of
8  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9  * GNU General Public License for more details.
10  *
11  * You should have received a copy of the GNU General Public License
12  * along with this program. If not, see <http://www.gnu.org/licenses/>.
13  *
14  */
25 /* standard libraries */
26 #include <stdint.h> // standard integer types
27 #include <stdlib.h> // general utilities
28 
29 /* STM32 (including CM3) libraries */
30 #include <libopencmsis/core_cm3.h> // Cortex M3 utilities
31 #include <libopencm3/stm32/rcc.h> // real-time control clock library
32 #include <libopencm3/stm32/gpio.h> // general purpose input output library
33 #include <libopencm3/stm32/timer.h> // timer utilities
34 
35 #include "global.h" // global utilities
36 #include "microwire_master.h" // microwire header and definitions
37 
41 #define MICROWIRE_MASTER_SDO_PORT A
42 #define MICROWIRE_MASTER_SDO_PIN 0
43 #define MICROWIRE_MASTER_SDI_PORT A
44 #define MICROWIRE_MASTER_SDI_PIN 2
45 #define MICROWIRE_MASTER_SCK_PORT A
46 #define MICROWIRE_MASTER_SCK_PIN 4
52 #define MICROWIRE_MASTER_TIMER 4
56 uint8_t mirowire_master_address_size = 0;
57 
59 
60 void microwire_master_setup(uint32_t frequency, bool organization_x16, uint8_t address_size)
61 {
62  // sanity checks
63  if (0==frequency || 0==address_size) {
64  return;
65  }
66  mirowire_master_address_size = address_size; // save address size
67  mirowire_master_organization_x16 = organization_x16; // save organisation
68 
69  // setup GPIO
70  rcc_periph_clock_enable(RCC_GPIO(MICROWIRE_MASTER_SDO_PORT)); // enable clock for GPIO domain for SDO signal
71  gpio_set_mode(GPIO(MICROWIRE_MASTER_SDO_PORT), GPIO_MODE_OUTPUT_10_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, GPIO(MICROWIRE_MASTER_SDO_PIN)); // set SDO signal as output (controlled by the master)
72  gpio_clear(GPIO(MICROWIRE_MASTER_SDO_PORT), GPIO(MICROWIRE_MASTER_SDO_PIN)); // SDO is idle low
73  rcc_periph_clock_enable(RCC_GPIO(MICROWIRE_MASTER_SDI_PORT)); // enable clock for GPIO domain for SDI signal
74  gpio_set_mode(GPIO(MICROWIRE_MASTER_SDI_PORT), GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, GPIO(MICROWIRE_MASTER_SDI_PIN)); // set SDI signal as output (controlled by the slave)
75  rcc_periph_clock_enable(RCC_GPIO(MICROWIRE_MASTER_SCK_PORT)); // enable clock for GPIO domain for SCK signal
76  gpio_set_mode(GPIO(MICROWIRE_MASTER_SCK_PORT), GPIO_MODE_OUTPUT_10_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, GPIO(MICROWIRE_MASTER_SCK_PIN)); // set SCK signal as output (controlled by the master)
77  gpio_clear(GPIO(MICROWIRE_MASTER_SCK_PORT), GPIO(MICROWIRE_MASTER_SCK_PIN)); // SCK is idle low
78 
79  // setup timer to generate timing for the signal
80  rcc_periph_clock_enable(RCC_TIM(MICROWIRE_MASTER_TIMER)); // enable clock for timer domain
81  timer_reset(TIM(MICROWIRE_MASTER_TIMER)); // reset timer state
82  timer_set_mode(TIM(MICROWIRE_MASTER_TIMER), TIM_CR1_CKD_CK_INT, TIM_CR1_CMS_EDGE, TIM_CR1_DIR_UP); // set timer mode, use undivided timer clock, edge alignment (simple count), and count up
83  uint16_t prescaler = rcc_ahb_frequency/(frequency*2)/(uint32_t)(1<<16)+1; // calculate prescaler for most accurate timing for this speed
84  timer_set_prescaler(TIM(MICROWIRE_MASTER_TIMER), prescaler-1); // set calculated prescaler
85  uint16_t period = (rcc_ahb_frequency/prescaler)/(frequency*2); // calculate period to get most accurate timing based on the calculated prescaler
86  timer_set_period(TIM(MICROWIRE_MASTER_TIMER), period-1); // set calculated period
87  timer_update_on_overflow(TIM(MICROWIRE_MASTER_TIMER)); // only use counter overflow as UEV source (use overflow as timeout)
88  SCB_SCR |= SCB_SCR_SEVEONPEND; // enable wake up on event (instead of using ISR)
89  timer_enable_irq(TIM(MICROWIRE_MASTER_TIMER), TIM_DIER_UIE); // enable update interrupt for timer
90 }
91 
93 static void microwire_master_wait_clock(void)
94 {
95  while ( !timer_get_flag(TIM(MICROWIRE_MASTER_TIMER), TIM_SR_UIF)) { // wait for timer overflow event for clock change
96  __asm__("wfe"); // go to sleep and wait for event
97  }
98  timer_clear_flag(TIM(MICROWIRE_MASTER_TIMER), TIM_SR_UIF); // clear timer flag
99  nvic_clear_pending_irq(NVIC_TIM_IRQ(MICROWIRE_MASTER_TIMER)); // clear IRQ flag (else event doesn't wake up)
100 
101 }
102 
106 static void microwire_master_send_bit(bool bit)
107 {
108  if (bit) {
109  gpio_set(GPIO(MICROWIRE_MASTER_SDO_PORT), GPIO(MICROWIRE_MASTER_SDO_PIN)); // set '1' on output
110  } else {
111  gpio_clear(GPIO(MICROWIRE_MASTER_SDO_PORT), GPIO(MICROWIRE_MASTER_SDO_PIN)); // set '0' on output
112  }
113  microwire_master_wait_clock(); // wait for clock timing
114  gpio_set(GPIO(MICROWIRE_MASTER_SCK_PORT), GPIO(MICROWIRE_MASTER_SCK_PIN)); // make rising edge for slave to sample
115  microwire_master_wait_clock(); // keep output signal stable while clock is high
116  gpio_clear(GPIO(MICROWIRE_MASTER_SCK_PORT), GPIO(MICROWIRE_MASTER_SCK_PIN)); // put clock back to idle
117 }
118 
123 static void microwire_master_start(uint8_t operation, uint32_t address)
124 {
125  // to sanity checks
126  if (0==mirowire_master_address_size) { // can't send address
127  return;
128  }
129 
130  // initial setup
131  gpio_clear(GPIO(MICROWIRE_MASTER_SCK_PORT), GPIO(MICROWIRE_MASTER_SCK_PIN)); // ensure clock is low (to sample on rising edge)
132  timer_set_counter(TIM(MICROWIRE_MASTER_TIMER),0); // reset timer counter
133  timer_clear_flag(TIM(MICROWIRE_MASTER_TIMER), TIM_SR_UIF); // clear timer flag
134  nvic_clear_pending_irq(NVIC_TIM_IRQ(MICROWIRE_MASTER_TIMER)); // clear IRQ flag (else event doesn't wake up)
135  timer_enable_counter(TIM(MICROWIRE_MASTER_TIMER)); // start timer to generate timing
136 
137  // send '1' start bit
138  microwire_master_send_bit(true); // send start bit
139  // send two bits operation code
140  if (operation&0x2) { // send first bit (MSb first)
141  microwire_master_send_bit(true); // send '1'
142  } else {
143  microwire_master_send_bit(false); // send '2'
144  }
145  if (operation&0x1) { // send second bit (LSb last)
146  microwire_master_send_bit(true); // send '1'
147  } else {
148  microwire_master_send_bit(false); // send '2'
149  }
150 
151  // send address
152  for (uint8_t bit = mirowire_master_address_size; bit > 0; bit--) {
153  if ((address>>(bit-1))&0x01) {
154  microwire_master_send_bit(true); // send '1' address bit
155  } else {
156  microwire_master_send_bit(false); // send '0' address bit
157  }
158  }
159  gpio_clear(GPIO(MICROWIRE_MASTER_SDO_PORT), GPIO(MICROWIRE_MASTER_SDO_PIN)); // ensure output is idle low (could be floating)
160 }
161 
163 static void microwire_master_stop(void)
164 {
165  timer_disable_counter(TIM(MICROWIRE_MASTER_TIMER)); // disable timer
166  timer_set_counter(TIM(MICROWIRE_MASTER_TIMER),0); // reset timer counter
167  timer_clear_flag(TIM(MICROWIRE_MASTER_TIMER), TIM_SR_UIF); // clear timer flag
168  nvic_clear_pending_irq(NVIC_TIM_IRQ(MICROWIRE_MASTER_TIMER)); // clear IRQ flag
169  gpio_clear(GPIO(MICROWIRE_MASTER_SCK_PORT), GPIO(MICROWIRE_MASTER_SCK_PIN)); // ensure clock is idle low
170  gpio_clear(GPIO(MICROWIRE_MASTER_SDO_PORT), GPIO(MICROWIRE_MASTER_SDO_PIN)); // ensure output is idle low
171 }
172 
173 
177 static bool microwire_master_read_bit(void)
178 {
179  microwire_master_wait_clock(); // wait for clock timing
180  gpio_set(GPIO(MICROWIRE_MASTER_SCK_PORT), GPIO(MICROWIRE_MASTER_SCK_PIN)); // make rising edge for slave to output data
181  microwire_master_wait_clock(); // wait for signal to be stable
182  gpio_clear(GPIO(MICROWIRE_MASTER_SCK_PORT), GPIO(MICROWIRE_MASTER_SCK_PIN)); // set clock low again
183  return 0!=gpio_get(GPIO(MICROWIRE_MASTER_SDI_PORT), GPIO(MICROWIRE_MASTER_SDI_PIN)); // read input signal
184 }
185 
186 void microwire_master_read(uint32_t address, uint16_t* data, size_t length)
187 {
188  // to sanity checks
189  if (NULL==data || 0==length || 0==mirowire_master_address_size) { // can't save data
190  return;
191  }
192 
193  microwire_master_start(0x02, address); // send '10' READ instruction and memory address
194 
195  // there should already be a '0' dummy bit
196  if (0!=gpio_get(GPIO(MICROWIRE_MASTER_SDI_PORT), GPIO(MICROWIRE_MASTER_SDI_PIN))) { // the dummy bit wasn't '0'
197  goto clean;
198  }
199 
200  // read data
201  for (size_t i=0; i<length; i++) {
202  for (uint8_t b=(mirowire_master_organization_x16 ? 16 : 8); b>0; b--) {
203  if (microwire_master_read_bit()) { // read bit, MSb first
204  data[i] |= (1<<(b-1)); // set bit
205  } else {
206  data[i] &= ~(1<<(b-1)); // clear bit
207  }
208  }
209  }
210 
211 clean:
212  microwire_master_stop(); // stop communication and clean up
213 }
214 
216 {
217  // to sanity checks
218  if (mirowire_master_address_size<2) { // can't send '11...' address
219  return;
220  }
221 
222  microwire_master_start(0x0, 0x3<<(mirowire_master_address_size-2)); // send '00' WEN operation code and '11...' address
223  microwire_master_stop(); // clean up
224 }
225 
227 {
228  // to sanity checks
229  if (mirowire_master_address_size<2) { // can't send '00...' address
230  return;
231  }
232 
233  microwire_master_start(0x0, 0); // send '00' WDS operation code and '00...' address
234  microwire_master_stop(); // clean up
235 }
236 
237 void microwire_master_write(uint32_t address, uint16_t data)
238 {
239  // to sanity checks
240  if (0==mirowire_master_address_size) { // can't send address
241  return;
242  }
243 
244  microwire_master_start(0x01, address); // send '01' WRITE operation code and memory address
245 
246  // write data (MSb first)
247  for (uint8_t b=(mirowire_master_organization_x16 ? 16 : 8); b>0; b--) {
248  if (data&(1<<(b-1))) { // bit is set
249  microwire_master_send_bit(true); // send '1' data bit
250  } else {
251  microwire_master_send_bit(false); // send '0' data bit
252  }
253  }
254 
255  microwire_master_stop(); // clean up
256 }
257 
259 {
260 
261  // initial setup
262  gpio_clear(GPIO(MICROWIRE_MASTER_SCK_PORT), GPIO(MICROWIRE_MASTER_SCK_PIN)); // ensure clock is low (to sample on rising edge)
263  timer_set_counter(TIM(MICROWIRE_MASTER_TIMER),0); // reset timer counter
264  timer_clear_flag(TIM(MICROWIRE_MASTER_TIMER), TIM_SR_UIF); // clear timer flag
265  nvic_clear_pending_irq(NVIC_TIM_IRQ(MICROWIRE_MASTER_TIMER)); // clear IRQ flag (else event doesn't wake up)
266  timer_enable_counter(TIM(MICROWIRE_MASTER_TIMER)); // start timer to generate timing
267 
268 
269  // SDI low on busy, high on ready, clock is ignored
270  while (!microwire_master_read_bit()); // wait until slave is ready
271 
272  microwire_master_stop(); // clean up
273 }
274 
275 void microwire_master_erase(uint32_t address)
276 {
277  // sanity checks
278  if (0==mirowire_master_address_size) { // can't send address
279  return;
280  }
281 
282  microwire_master_start(0x03, address); // send '11' ERASE operation code and memory address
283  microwire_master_stop(); // clean up
284 }
285 
287 {
288  // sanity checks
289  if (mirowire_master_address_size<2) { // can't send '11...' address
290  return;
291  }
292 
293  microwire_master_start(0x00, 0x2<<(mirowire_master_address_size-2)); // send '00' ERAL operation code and '10...' address
294  microwire_master_stop(); // clean up
295 }
296 
297 void microwire_master_write_all(uint16_t data)
298 {
299  // sanity checks
300  if (0==mirowire_master_address_size) { // can't send address
301  return;
302  }
303 
304  microwire_master_start(0x00, 0x1<<(mirowire_master_address_size-2)); // send '00' WRAL operation code and '01...' address
305  // write data (MSb first)
306  for (uint8_t b=(mirowire_master_organization_x16 ? 16 : 8); b>0; b--) {
307  if (data&(1<<(b-1))) { // bit is set
308  microwire_master_send_bit(true); // send '1' data bit
309  } else {
310  microwire_master_send_bit(false); // send '0' data bit
311  }
312  }
313 
314  microwire_master_stop(); // clean up
315 }
void microwire_master_setup(uint32_t frequency, bool organization_x16, uint8_t address_size)
setup microwire peripheral
static void microwire_master_stop(void)
stop microwire communication and end all activities
static void microwire_master_wait_clock(void)
wait for clock tick used to synchronise communication
void microwire_master_wait_ready(void)
wait until slave is ready after a write or erase
#define RCC_GPIO(x)
get RCC for GPIO based on GPIO identifier
Definition: global.h:105
static void microwire_master_send_bit(bool bit)
send bit over microwire
#define MICROWIRE_MASTER_SDI_PIN
SDO input signal pin (to be connected on Q slave signal)
void microwire_master_write_disable(void)
disable write and erase operations
void microwire_master_erase_all(void)
erase all memory
void microwire_master_write(uint32_t address, uint16_t data)
write data to slave memory
#define NVIC_TIM_IRQ(x)
get NVIC IRQ for timer base on TIM identifier
Definition: global.h:111
#define MICROWIRE_MASTER_SDO_PORT
SDO output signal port (to be connected on D slave signal)
uint8_t mirowire_master_address_size
address size used in operations (slave specific)
#define MICROWIRE_MASTER_SCK_PORT
SCK output signal port (to be connected on C slave signal)
#define MICROWIRE_MASTER_TIMER
timer peripheral
global definitions and methods (API)
#define GPIO(x)
get GPIO based on GPIO identifier
Definition: global.h:103
#define MICROWIRE_MASTER_SDI_PORT
SDO input signal port (to be connected on Q slave signal)
void microwire_master_read(uint32_t address, uint16_t *data, size_t length)
read data from slave memory
#define RCC_TIM(x)
get RCC for timer based on TIM identifier
Definition: global.h:109
static bool microwire_master_read_bit(void)
read bit from microwire communication
void microwire_master_write_enable(void)
enable write and erase operations
void microwire_master_write_all(uint16_t data)
write data to all slave memory
#define MICROWIRE_MASTER_SDO_PIN
SDO output signal pin (to be connected on D slave signal)
static void microwire_master_start(uint8_t operation, uint32_t address)
initialize microwire communication and send header (with leading start bit &#39;1&#39;)
void microwire_master_erase(uint32_t address)
erase memory
bool mirowire_master_organization_x16
organization used (true=x16, false=x8)
#define TIM(x)
get TIM based on TIM identifier
Definition: global.h:107
#define MICROWIRE_MASTER_SCK_PIN
SCK output signal pin (to be connected on C slave signal)
library to communicate using microwore as master (API)