aboutsummaryrefslogtreecommitdiffstats
path: root/examples/test-spi-roundtrip.cpp
blob: 257303b33fe6592378fd98f1374a3db5f864ac70 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
/*
 * Polling SPI loopback test.
 *
 * Bob is nowhere to be found, so Alice decides to talk to herself.
 *
 * Instructions: Connect SPI2 (Alice) to herself (i.e., MISO to MOSI).
 * Connect to Alice via Serial2 at 115200 baud.  Press any key to start.
 *
 * Alice will talk to herself for a little while.  The sketch will
 * report if Alice can't hear anything she says.  She'll then start
 * talking forever at various frequencies, bit orders, and modes.  Use
 * an oscilloscope to make sure she's not trying to lie about any of
 * those things.
 *
 * This file is released into the public domain.
 *
 * Author: Marti Bolivar <mbolivar@leaflabs.com>
 */

#include "wirish.h"

HardwareSPI alice(2);

#define NFREQS 8
const SPIFrequency spi_freqs[] = {
    SPI_140_625KHZ,
    SPI_281_250KHZ,
    SPI_562_500KHZ,
    SPI_1_125MHZ,
    SPI_2_25MHZ,
    SPI_4_5MHZ,
    SPI_9MHZ,
    SPI_18MHZ,
};

#define TEST_BUF_SIZE 10
uint8 test_buf[TEST_BUF_SIZE] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};

void bad_assert(const char* file, int line, const char* exp) {
    Serial2.println();
    Serial2.print("ERROR: FAILED ASSERT(");
    Serial2.print(exp);
    Serial2.print("): ");
    Serial2.print(file);
    Serial2.print(": ");
    Serial2.println(line);
    throb();
}

#undef ASSERT
#define ASSERT(exp)                                    \
    if (exp) {                                         \
    } else {                                           \
        bad_assert(__FILE__, __LINE__, #exp);          \
    }

void haveConversation(uint32 bitOrder);
void soliloquies(uint32 bitOrder);

void setup() {
    pinMode(BOARD_LED_PIN, OUTPUT);
    Serial2.begin(115200);
    Serial2.println();
    Serial2.print("** SPI test ready.  Press any key to start.");
    while (!Serial2.available())
        ;
    Serial2.read();
}

void loop() {
    Serial2.println("** Having a conversation, MSB first");
    haveConversation(MSBFIRST);

    Serial2.println("** Having a conversation, LSB first");
    haveConversation(LSBFIRST);

    Serial2.println();
    Serial2.println("*** All done!  It looks like everything worked.");
    Serial2.println();

    Serial2.println("** Alice will now wax eloquent in various styles. "
                    "Press any key for the next configuration.");
    soliloquies(MSBFIRST);
    soliloquies(LSBFIRST);

    while (true)
        ;
}

void printFrequencyString(SPIFrequency frequency);
void chat(SPIFrequency frequency, uint32 bitOrder, uint32 mode);

void haveConversation(uint32 bitOrder) {
    for (int f = 0; f < NFREQS; f++) {
        for (int mode = 0; mode < 4; mode++) {
            chat(spi_freqs[f], bitOrder, mode);
            delay(10);
        }
    }
}

void chat(SPIFrequency frequency, uint32 bitOrder, uint32 mode) {
    Serial2.print("Having a chat.\tFrequency: ");
    printFrequencyString(frequency);
    Serial2.print(",\tbitOrder: ");
    Serial2.print(bitOrder == MSBFIRST ? "MSB" : "LSB");
    Serial2.print(",\tmode: ");
    Serial2.print(mode);
    Serial2.print(".");

    Serial2.print(" [1] ");
    alice.begin(frequency, bitOrder, mode);

    Serial2.print(" [2] ");
    uint32 txed = 0;
    while (txed < TEST_BUF_SIZE) {
        ASSERT(alice.transfer(test_buf[txed]) == test_buf[txed]);
        txed++;
    }

    Serial2.print(" [3] ");
    alice.end();

    Serial2.println(" ok.");
}

void soliloquy(SPIFrequency freq, uint32 bitOrder, uint32 mode);

void soliloquies(uint32 bitOrder) {
    for (int f = 0; f < NFREQS; f++) {
        for (int mode = 0; mode < 4; mode++) {
            soliloquy(spi_freqs[f], bitOrder, mode);
        }
    }
}

void soliloquy(SPIFrequency frequency, uint32 bitOrder, uint32 mode) {
    const uint8 repeat = 0xAE;
    Serial2.print("Alice is giving a soliloquy (repeating 0x");
    Serial2.print(repeat, HEX);
    Serial2.print("). Frequency: ");
    printFrequencyString(frequency);
    Serial2.print(", bitOrder: ");
    Serial2.print(bitOrder == MSBFIRST ? "big-endian" : "little-endian");
    Serial2.print(", SPI mode: ");
    Serial2.println(mode);

    alice.begin(frequency, bitOrder, mode);
    while (!Serial2.available()) {
        alice.write(repeat);
        delayMicroseconds(200);
    }
    Serial2.read();
}

void printFrequencyString(SPIFrequency frequency) {
    switch (frequency) {
    case SPI_18MHZ:
        Serial2.print("18 MHz");
        break;
    case SPI_9MHZ:
        Serial2.print("9 MHz");
        break;
    case SPI_4_5MHZ:
        Serial2.print("4.5 MHz");
        break;
    case SPI_2_25MHZ:
        Serial2.print("2.25 MHZ");
        break;
    case SPI_1_125MHZ:
        Serial2.print("1.125 MHz");
        break;
    case SPI_562_500KHZ:
        Serial2.print("562.500 KHz");
        break;
    case SPI_281_250KHZ:
        Serial2.print("281.250 KHz");
        break;
    case SPI_140_625KHZ:
        Serial2.print("140.625 KHz");
        break;
    }
}

// Force init to be called *first*, i.e. before static object allocation.
// Otherwise, statically allocated objects that need libmaple may fail.
__attribute__((constructor)) void premain() {
    init();
}

int main(void) {
    setup();
    while (true) {
        loop();
    }
    return 0;
}