1 /* Grandstream BT20x driver as an extension to the tic55x driver
3 * Ideally, all this would be is wiring to the generic functions of
4 * chips connected to the DSP. And of course a lot of register setup
5 * code. In practice, it is not as sharply divided, sometimes for
6 * reasons of efficiency, sometimes for other reasons. The ideal is
7 * the best judgement however, and any debate on where code should go
8 * should be based on this ideal plus the realism that too much
9 * indirection will slow down a program that is going to deal with
10 * static hardware anyway.
12 * This file is part of 0cpm Firmerware.
14 * 0cpm Firmerware is Copyright (c)2011 Rick van Rein, OpenFortress.
16 * 0cpm Firmerware is free software: you can redistribute it and/or
17 * modify it under the terms of the GNU General Public License as
18 * published by the Free Software Foundation, version 3.
20 * 0cpm Firmerware is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
25 * You should have received a copy of the GNU General Public License
26 * along with 0cpm Firmerware. If not, see <http://www.gnu.org/licenses/>.
39 #include <0cpm/timer.h>
43 #include <0cpm/show.h>
44 #include <0cpm/flash.h>
46 #include <0cpm/cons.h>
48 #include <bottom/ht162x.h>
49 #include <bottom/ksz8842.h>
53 /******** EXTERNAL INTERRUPTS SERVICE ROUTINES ********/
56 interrupt void tic55x_int0_isr (void) {
57 tic55x_top_has_been_interrupted = true;
58 ksz8842_interrupt_handler ();
62 interrupt void tic55x_int1 (void) {
63 tic55x_top_has_been_interrupted = true;
67 interrupt void tic55x_int2 (void) {
68 tic55x_top_has_been_interrupted = true;
72 interrupt void tic55x_int3 (void) {
73 tic55x_top_has_been_interrupted = true;
80 /******** FLASH PARTITION ACCESS ********/
83 /* An external definition (usually in phone-specific code)
84 * contains an array of at least one entry of flashpart
85 * structures. Only the last will have the FLASHPART_FLAG_LAST
88 * There will usually be one partition with name ALLFLASH.BIN
89 * that covers the entire flash memory, including things that
90 * may not actually be in any partition. Usually, this is the
91 * last entry in the flash partition table.
93 struct flashpart bottom_flash_partition_table [] = {
94 { FLASHPART_FLAG_LAST, "ALLFLASH.BIN", 0, 4096 }
98 /* Read a 512-byte block from flash.
99 * The return value indicates success.
101 bool bottom_flash_read (uint16_t blocknr, uint8_t data [512]) {
104 if (blocknr >= 4096) {
107 flashidx = ((uint32_t) blocknr) * 256;
109 uint16_t sample = flash_16 [flashidx];
111 // data [ctr++] = (sample >> 24) & 0xff;
112 // data [ctr++] = (sample >> 16) & 0xff;
113 data [ctr++] = (sample >> 8) & 0xff;
114 data [ctr++] = sample & 0xff;
120 /* Write a 512-byte block to flash. It is assumed that this
121 * is done sequentially; any special treatment for a header
122 * page will be done by the bottom layer, not the top.
123 * The return value indicates success.
125 bool boot_flash_write (uint16_t blocknr, uint8_t data [512]) {
130 /* Retrieve the current phone's MAC address from Flash.
132 void bottom_flash_get_mac (uint8_t mac [6]) {
133 uint32_t flashidx = flash_offset_mymac;
136 uint16_t sample = flash_16 [flashidx];
138 mac [ctr++] = (sample >> 8) & 0xff;
139 mac [ctr++] = sample & 0xff;
145 /******** TLV320AIC20K PROGRAMMING ACCESS OVER I2C ********/
148 /* The codec can be programmed over I2C, so the low-level routines
149 * for driving the codec end up passing bytes over I2C. The
150 * procedure of cycling through subregisters is not performed here.
153 void tlv320aic2x_setreg (uint8_t channel, uint8_t reg, uint8_t val) {
154 // Wait as long as the bus is busy
155 bottom_led_set (LED_IDX_MESSAGE, 1);
156 while (I2CSTR & REGVAL_I2CSTR_BB) {
159 // bottom_printf ("I2C.pre = 0x%04x,0x%04x\n", (intptr_t) I2CSTR, (intptr_t) I2CMDR);
160 // Set transmission mode for 2 bytes to "channel"
161 I2CSAR = 0x40 | channel;
162 //TODO// I2CSAR = 0x00; // Broadcast
165 // Send the register index
166 // Initiate the transfer by setting STT and STP flags
167 I2CMDR = REGVAL_I2CMDR_TRX | REGVAL_I2CMDR_MST | REGVAL_I2CMDR_STT | REGVAL_I2CMDR_STP | REGVAL_I2CMDR_NORESET | REGVAL_I2CMDR_FREE | REGVAL_I2CMDR_BC_8;
168 // bottom_printf ("I2C.set = 0x%04x,0x%04x\n", (intptr_t) I2CSTR, (intptr_t) I2CMDR);
169 // Wait for the START condition to occur
170 // bottom_led_set (LED_IDX_HANDSET, 1);
171 while (I2CMDR & REGVAL_I2CMDR_STT) {
174 // bottom_printf ("I2C.stt = 0x%04x,0x%04x\n", (intptr_t) I2CSTR, (intptr_t) I2CMDR);
175 // bottom_led_set (LED_IDX_HANDSET, 0);
176 // Wait until the I2C bus is ready, then send the value
177 // bottom_led_set (LED_IDX_SPEAKERPHONE, 1);
178 while (!(I2CSTR & REGVAL_I2CSTR_XRDY)) {
179 if (I2CSTR & REGVAL_I2CSTR_NACK) {
180 // bottom_printf ("I2C received NACK\n");
181 I2CSTR = REGVAL_I2CSTR_NACK;
182 I2CMDR = REGVAL_I2CMDR_MST | REGVAL_I2CMDR_STP | REGVAL_I2CMDR_NORESET | REGVAL_I2CMDR_FREE | REGVAL_I2CMDR_BC_8;
186 // bottom_printf ("I2C.xrdy = 0x%04x,0x%04x\n", (intptr_t) I2CSTR, (intptr_t) I2CMDR);
187 // bottom_led_set (LED_IDX_SPEAKERPHONE, 0);
189 // Wait for the STOP condition to occur
190 while (I2CMDR & REGVAL_I2CMDR_STP) {
193 // bottom_printf ("I2C.post = 0x%04x,0x%04x\n", (intptr_t) I2CSTR, (intptr_t) I2CMDR);
194 bottom_led_set (LED_IDX_MESSAGE, 0);
197 uint8_t tlv320aic2x_getreg (uint8_t channel, uint8_t reg) {
200 bottom_led_set (LED_IDX_MESSAGE, 1);
201 // bottom_led_set (LED_IDX_HANDSET, 0);
202 // Wait as long as the bus is busy
203 while (I2CSTR & REGVAL_I2CSTR_BB) {
206 // Set transmission mode for 1 byte to "channel"
207 I2CSAR = 0x40 | channel;
208 //TODO// I2CSAR = 0x00; // Broadcast
211 // Send the register index
212 // Initiate the transfer by setting STT flag, but withhold STP
213 I2CMDR = REGVAL_I2CMDR_TRX | REGVAL_I2CMDR_MST | REGVAL_I2CMDR_STT | /* REGVAL_I2CMDR_STP | */ REGVAL_I2CMDR_NORESET | REGVAL_I2CMDR_FREE | REGVAL_I2CMDR_BC_8;
214 // Wait until the START condition has occurred
215 while (I2CMDR & REGVAL_I2CMDR_STT) {
218 // ...send address and write mode bit...
219 // bottom_led_set (LED_IDX_HANDSET, 1);
220 // Wait until ready to setup for receiving
221 // while (I2CMDR & REGVAL_I2CMDR_STP) {
222 while (I2CSTR & (REGVAL_I2CSTR_XRDY | REGVAL_I2CSTR_XSMT) != (REGVAL_I2CSTR_XRDY | REGVAL_I2CSTR_XSMT)) {
223 if (I2CSTR & (REGVAL_I2CSTR_NACK | REGVAL_I2CSTR_AL)) {
224 I2CSTR = REGVAL_I2CSTR_NACK | REGVAL_I2CSTR_AL;
225 I2CMDR = REGVAL_I2CMDR_MST | REGVAL_I2CMDR_STP | REGVAL_I2CMDR_NORESET | REGVAL_I2CMDR_FREE | REGVAL_I2CMDR_BC_8;
229 // bottom_led_set (LED_IDX_HANDSET, 0);
231 // Restart with STT flag, also permit stop with STP; do not set TRX
232 I2CMDR = REGVAL_I2CMDR_MST | /* REGVAL_I2CMDR_STT | */ REGVAL_I2CMDR_STP | REGVAL_I2CMDR_NORESET | REGVAL_I2CMDR_FREE | REGVAL_I2CMDR_BC_8;
234 while (!(I2CSTR & REGVAL_I2CSTR_RRDY)) {
236 if (I2CSTR & REGVAL_I2CSTR_NACK) {
237 I2CSTR = REGVAL_I2CSTR_NACK;
238 // I2CMDR = REGVAL_I2CMDR_MST | REGVAL_I2CMDR_STP | REGVAL_I2CMDR_NORESET | REGVAL_I2CMDR_FREE | REGVAL_I2CMDR_BC_8;
245 bottom_led_set (LED_IDX_MESSAGE, 0);
250 /******** TLV320AIC20K DATA ACCESS OVER MCBSP1 ********/
253 #define BUFSZ (80*24)
255 static volatile int16_t samplebuf_play [BUFSZ];
256 static volatile int16_t samplebuf_record [BUFSZ];
258 static uint16_t samplebuf_blocksize = 80;
259 static uint16_t samplebuf_wrapindex = BUFSZ;
261 /* The buffer is a contiguous array of samples, made accessible
262 * to the top layer per block. Upon setting sample rate and
263 * block size, all pointers start at the beginning of the buffer.
264 * While processing, the pointers advance with one blocksize at
265 * a time; they wrap around if there is not enough space left to
266 * cover a complete block within the bounds of the sample buffer.
268 * The buffer has three types of areas, each with their own
269 * consumer/producer relationships. The areas are the same for
270 * the playback and recording buffer. They are:
271 * - playable: Can be filled be the codec for playback
272 * - dmaready: Can be played/recorded through lockstep DMA
273 * - recordable: Can be processed by the codec in recording
274 * Each of these areas is marked with an index pointer; their
275 * ends +1 are marked by another index pointer, as follows:
278 * playable play0 rec0
279 * dmaready dma0 play0
280 * recordable rec0 dma0
282 * DMA is possible if the dmaready area is non-empty, so if
283 * dma0 != play0. After DMA has transferred a block,
284 * the dma0 pointer is incremented, and this is checked.
286 * bottom_record_claim() succeeds if rec0 != dma0, and when
287 * bottom_record_release() is called, rec0 increments. Note
288 * that bottom_echo_claim() applies the same condition, but
289 * it returns the rec0 offset of the playbuf, instead of the
290 * rec0 offset in the recbuf as is returned by record_claim.
292 * bottom_play_claim() succeeds if play0 != rec0 *or* if the
293 * buffer is empty, which is noticed if DMA is not active. This
294 * means that playback is the first thing to start when a new
295 * set of index pointers is setup with zero values. When the
296 * bottom_play_release() is called, play0 increments, and the
297 * DMA conditions are evaluated.
300 volatile bool dma_active = false;
301 /*TODO:static*/ volatile uint16_t bufofs_play0 = 0;
302 /*TODO:static*/ volatile uint16_t bufofs_dma0 = 0;
303 /*TODO:static*/ volatile uint16_t bufofs_rec0 = 0;
306 inline void bottom_bufferdma_progress (uint8_t chan) {
307 bool recordinghint = (bufofs_dma0 == bufofs_rec0);
308 bufofs_dma0 = (bufofs_dma0 + samplebuf_blocksize) % samplebuf_wrapindex;
309 if (bufofs_dma0 == bufofs_play0) {
310 SPCR2_1 &= ~REGVAL_SPCR2_FRST_NOTRESET; // Stop DMA
314 top_codec_can_record (chan);
318 int16_t *bottom_play_claim (uint8_t chan) {
319 if ((!dma_active) || (bufofs_play0 != bufofs_rec0)) {
320 return (int16_t *) &samplebuf_play [bufofs_play0];
326 void bottom_play_release (uint8_t chan) {
327 bool dmahint = (bufofs_play0 == bufofs_dma0);
328 bufofs_play0 = (bufofs_play0 + samplebuf_blocksize) % samplebuf_wrapindex;
330 //TODO// Following 5 lines can be done much earlier
331 (void) DRR1_1; // Flag down RFULL
333 DMACCR_0 |= REGVAL_DMACCR_EN;
334 DXR1_1 = DXR1_1; // Flag down XEMPTY
335 DMACCR_1 |= REGVAL_DMACCR_EN;
336 SPCR2_1 |= REGVAL_SPCR2_FRST_NOTRESET; // Start DMA
341 int16_t *bottom_record_claim (uint8_t chan) {
342 if (bufofs_rec0 != bufofs_dma0) {
343 return (int16_t *) &samplebuf_record [bufofs_rec0];
349 int16_t *bottom_echo_claim (uint8_t chan) {
350 if (bufofs_rec0 != bufofs_dma0) {
351 return (int16_t *) &samplebuf_play [bufofs_rec0];
357 void bottom_record_release (uint8_t chan) {
358 bool playbackhint = (bufofs_rec0 == bufofs_play0);
359 bufofs_rec0 = (bufofs_rec0 + samplebuf_blocksize) % samplebuf_wrapindex;
361 top_codec_can_play (chan);
365 static int TODO_setratectr = 0;
367 /* Set a frequency divisor for the intended sample rate */
368 //TODO// Not all this code is properly split between generic TLV and specific BT200
369 void tlv320aic2x_set_samplerate (uint8_t chan, uint32_t samplerate) {
371 SPCR2_1 |= REGVAL_SPCR2_GRST_NOTRESET | REGVAL_SPCR2_FRST_NOTRESET;
372 { uint32_t ctr = 100; while (ctr-- > 0) ; }
373 SPCR1_1 |= REGVAL_SPCR1_RRST_NOTRESET;
374 SPCR2_1 |= REGVAL_SPCR2_XRST_NOTRESET;
375 { uint32_t ctr = 10000; while (ctr-- > 0) ; }
376 DXR1_1 = DXR1_1; // Flag down XEMPTY
377 tlv320aic2x_setreg (chan, 3, 0x31); // Channel offline
378 { uint32_t ctr = 1000; while (ctr-- > 0) ; }
379 (void) DRR1_1; // Flag down RFULL
381 // Determine the dividors m, n and p
384 m = ( 30720000 / 16 ) / ( n * p * samplerate );
385 if ((m & 0x03) == 0x00) {
386 // Save PLL energy without compromising accuracy
387 p = 8; // Factor 2 -> 8 so multiplied by 4
388 m >>= 2; // Divide by 4
394 { uint8_t ip4 [4]; ip4 [0] = m; ip4 [1] = n; ip4 [2] = p; ip4 [3] = ++TODO_setratectr; bottom_show_ip4 (APP_LEVEL_CONNECTING, ip4); }
395 #ifdef CONFIG_FUNCTION_NETCONSOLE
396 bottom_printf ("TLV320AIC20K setting: M=%d, N=%d, P=%d\n", (intptr_t) m, (intptr_t) n, (intptr_t) p);
399 n &= 0x0f; // Ignore range problems?
401 // With the codec up and running, configure the sample rate
402 tlv320aic2x_setreg (chan, 4, 0x00 | (n << 3) | p);
403 tlv320aic2x_setreg (chan, 4, 0x80 | m);
404 { uint32_t ctr = 1000; while (ctr-- > 0) ; }
405 // #ifndef TODO_FS_ONLY_DURING_SOUND_IO
406 // SPCR2_1 |= REGVAL_SPCR2_GRST_NOTRESET | REGVAL_SPCR2_FRST_NOTRESET;
407 // SPCR1_1 |= REGVAL_SPCR1_RRST_NOTRESET;
408 // SPCR2_1 |= REGVAL_SPCR2_XRST_NOTRESET;
409 SPCR1_1 &= ~REGVAL_SPCR1_RRST_NOTRESET;
410 SPCR2_1 &= ~REGVAL_SPCR2_XRST_NOTRESET;
411 { uint32_t ctr = 10000; while (ctr-- > 0) ; }
412 SPCR2_1 &= ~ ( REGVAL_SPCR2_GRST_NOTRESET | REGVAL_SPCR2_FRST_NOTRESET );
413 { uint32_t ctr = 10000; while (ctr-- > 0) ; }
414 // SPCR2_1 &= ~ ( REGVAL_SPCR2_FRST_NOTRESET );
415 { uint32_t ctr = 10000; while (ctr-- > 0) ; }
417 samplerate = 12288000 / samplerate;
418 if (samplerate >= 4096) {
420 } else if (samplerate == 0) {
423 SRGR2_1 = REGVAL_SRGR2_CLKSM | REGVAL_SRGR2_FSGM | (samplerate - 1);
424 // #ifndef TODO_FS_ONLY_DURING_SOUND_IO
425 // SPCR2_1 |= REGVAL_SPCR2_GRST_NOTRESET | REGVAL_SPCR2_FRST_NOTRESET;
426 SPCR2_1 |= REGVAL_SPCR2_GRST_NOTRESET;
427 tlv320aic2x_setreg (chan, 3, 0x01); // Channel online
428 { uint32_t ctr = 1000; while (ctr-- > 0) ; }
429 // tlv320aic2x_setreg (chan, 4, 0x00 | (n << 3) | p);
430 // tlv320aic2x_setreg (chan, 4, 0x80 | m);
431 // { uint32_t ctr = 10000; while (ctr-- > 0) ; }
432 SPCR1_1 |= REGVAL_SPCR1_RRST_NOTRESET;
433 SPCR2_1 |= REGVAL_SPCR2_XRST_NOTRESET;
434 { uint32_t ctr = 1000; while (ctr-- > 0) ; }
435 //NOT_FOR_NEW_STYLE_BUFFERS// SPCR2_1 |= REGVAL_SPCR2_FRST_NOTRESET;
436 { uint32_t ctr = 10000; while (ctr-- > 0) ; }
437 DXR1_1 = DXR1_1; // Flag down XEMPTY
438 (void) DRR1_1; // Flag down RFULL
440 { uint32_t ctr = 10000; while (ctr-- > 0) ; }
444 void bottom_soundchannel_set_samplerate (uint8_t chan, uint32_t samplerate,
445 uint8_t blocksize, uint8_t upsample_play, uint8_t downsample_record) {
447 // Setup the buffersize of the sample buffers
448 samplebuf_blocksize = blocksize;
449 samplebuf_wrapindex = (BUFSZ / blocksize) * blocksize;
451 // Setup hardware with the requested sample rate (but no FRST generated)
452 tlv320aic2x_set_samplerate (chan, samplerate);
454 // Setup buffer index pointers at the start; effectively clearing all
461 /* A full frame of 64 samples has been recorded. See if space exists for
462 * another, otherwise disable DMA until a dmahint_play() restarts it.
463 * TODO: No processing needed for RX_DMA_IRQ, as TX_DMA_IRQ comes later.
465 interrupt void tic55x_dmac0_isr (void) {
466 #ifdef PREFER_OLD_STUFF
467 uint16_t irq = DMACSR_0; // Note causes and clear
468 tic55x_top_has_been_interrupted = true;
469 if ((available_record += 64) > (BUFSZ - 64)) {
470 SPCR2_1 &= ~REGVAL_SPCR2_XRST_NOTRESET;
471 SPCR2_1 |= REGVAL_SPCR2_XRST_NOTRESET;
472 DMACCR_0 &= ~REGVAL_DMACCR_EN;
473 // #ifdef TODO_FS_ONLY_DURING_SOUND_IO
474 // SPCR1_1 &= ~REGVAL_SPCR1_RRST_NOTRESET;
475 // if ((SPCR2_1 & REGVAL_SPCR2_XRST_NOTRESET) == 0) {
476 // SPCR2_1 &= ~ (REGVAL_SPCR2_GRST_NOTRESET | REGVAL_SPCR2_FRST_NOTRESET);
480 if (available_record >= threshold_record) {
481 top_codec_can_record (available_record);
486 /* A full frame of 64 samples has been played. See if another is availabe,
487 * otherwise disable DMA until a dmahint_record() restarts it.
489 interrupt void tic55x_dmac1_isr (void) {
490 #ifdef PREFER_OLD_STUFF
491 uint16_t irq = DMACSR_1; // Note causes and clear
493 tic55x_top_has_been_interrupted = true;
494 if ((available_play -= 64) < 64) {
495 // #ifdef TODO_FS_ONLY_DURING_SOUND_IO
496 // SPCR2_1 &= ~REGVAL_SPCR2_XRST_NOTRESET;
497 // if ((SPCR1_1 & REGVAL_SPCR1_RRST_NOTRESET) == 0) {
498 // SPCR2_1 &= ~ (REGVAL_SPCR2_GRST_NOTRESET | REGVAL_SPCR2_FRST_NOTRESET);
501 DMACCR_1 &= ~REGVAL_DMACCR_EN;
503 toplay = BUFSZ - available_play;
504 if (BUFSZ - available_play >= threshold_play) {
505 top_codec_can_play (available_play);
508 bottom_bufferdma_progress (0);
511 #ifdef PREFER_OLD_STUFF
512 /* Data has been removed from what was recorded. As a result,
513 * it may be possible to restart DMA channel 1 if it was disabled.
515 void dmahint_record (void) {
516 if (! (DMACCR_0 & REGVAL_DMACCR_EN)) {
517 if (available_record <= (BUFSZ - 64)) {
518 if (!(DMACCR_0 & REGVAL_DMACCR_EN)) {
519 (void) DRR1_1; // Flag down RFULL
521 DMACCR_0 |= REGVAL_DMACCR_EN;
522 // #ifdef TODO_FS_ONLY_DURING_SOUND_IO
523 // SPCR1_1 |= REGVAL_SPCR1_RRST_NOTRESET;
524 // SPCR2_1 |= REGVAL_SPCR2_GRST_NOTRESET | REGVAL_SPCR2_FRST_NOTRESET;
527 // bottom_printf ("dmahint_record() enabled DMA from %d bytes out of %d\n", (intptr_t) available_record, (intptr_t) BUFSZ);
533 #ifdef PREFER_OLD_STUFF
534 /* New data has been written for playback. As a result, it may
535 * be possible to restart DMA channel 0 if it was disabled.
537 void dmahint_play (void) {
538 if ((available_play >= 64) && ! (DMACCR_1 & REGVAL_DMACCR_EN)) {
539 DXR1_1 = DXR1_1; // Flag down XEMPTY
540 DMACCR_1 |= REGVAL_DMACCR_EN;
541 #ifdef CONFIG_FUNCTION_NETCONSOLE
542 bottom_printf ("dmahint_play() started playing DMA\n");
544 // #ifdef TODO_FS_ONLY_DURING_SOUND_IO
545 // SPCR2_1 |= REGVAL_SPCR2_XRST_NOTRESET | REGVAL_SPCR2_GRST_NOTRESET | REGVAL_SPCR2_FRST_NOTRESET;
548 //TODO:DEBUG// else bottom_printf ("dmahint_play() did not start playing -- available_play = %d\n", (intptr_t) available_play);
554 /******** HT162x LCD DRIVER LOW-LEVEL FUNCTIONS ********/
557 /* The program defines an array of LCDCMD_xxx to
558 * initialise the HT162x chip. The array should be
559 * terminated with HT162x_LCDCMD_DONE.
561 extern uint16_t ht162x_setup_cmdseq [] = {
562 HT162x_LCDPREFIX_CMD,
563 HT162x_LCDCMD_LCDOFF,
564 HT162x_LCDCMD_NORMAL,
565 HT162x_LCDCMD_RC256K,
568 HT162x_LCDCMD_TIMERDIS,
569 HT162x_LCDCMD_WDTDIS,
570 HT162x_LCDCMD_TONEOFF,
571 HT162x_LCDCMD_BIAS3_4,
572 HT162x_LCDCMD_TONE2K,
573 // Terminate the sequence:
578 /* Chip-enable or -disable the LCD driver */
579 void ht162x_chipselect (bool selected) {
581 IODATA &= ~ (1 << 1);
588 /* Send out a databit for the LCD driver, but do not clock it in */
589 static uint16_t kbdisp_outbuf = 0x0000;
590 void ht162x_databit_prepare (bool databit) {
592 kbdisp_outbuf &= ~0x4040;
593 kbdisp_outbuf |= 0x8080;
595 kbdisp_outbuf &= ~0xc0c0;
597 kbdisp = kbdisp_outbuf;
600 /* Clock in the database that was prepared for the LCD driver */
601 void ht162x_databit_commit (void) {
602 kbdisp_outbuf |= 0x4040;
603 kbdisp = kbdisp_outbuf;
607 /******** LCD-SPECIFIC FORM PAINTING ROUTINES ********/
610 /* Digit notations on the LCD's 7 segment displays */
611 uint8_t lcd7seg_digits [10] = {
612 0xaf, 0xa0, 0xcb, 0xe9, 0xe4, // 01234
613 0x6d, 0x6f, 0xa8, 0xef, 0xed // 56789
616 /* Alphabetic notations on the LCD's 7 segment displays */
617 uint8_t lcd7seg_alpha [26] = {
618 0xee, 0x67, 0x0f, 0xe3, 0x4f, // AbCdE
619 0x4e, 0x2f, 0xe6, 0x06, 0xa1, // FGHIJ
620 0x6e, 0x07, 0x6a, 0x62, 0x63, // kLMno
621 0xce, 0xec, 0x42, 0x6d, 0x47, // PQRST
622 0xa7, 0x23, 0x2b, // Uvw
626 /* Put a character into display byte idx, with ASCII code ch */
627 void ht162x_putchar (uint8_t idx, uint8_t ch, bool notify) {
628 uint8_t chup = ch & 0xdf;
630 if ((ch >= '0') && (ch <= '9')) {
631 lcd7seg = lcd7seg_digits [ch - '0'];
632 } else if ((chup >= 'A') && (chup <= 'Z')) {
633 lcd7seg = lcd7seg_alpha [chup - 'A'];
634 } else if (chup == 0x00) {
635 lcd7seg = 0x00; // space for chup one of 0x00 and 0x20
637 lcd7seg = 0x40; // dash
639 ht162x_dispdata [idx] = (ht162x_dispdata [idx] & 0x10) | lcd7seg;
641 ht162x_dispdata_notify (idx, idx);
645 uint8_t lcd_bars [8] = {
646 0x00, 0x20, 0x60, 0xe0, 0xe8, 0xec, 0xee, 0xef
649 /* Level indication for volume, showing the upper 3 bits of "level" */
650 void ht162x_audiolevel (uint8_t level) {
651 uint8_t bars = lcd_bars [level >> 5];
652 ht162x_dispdata [15] = (ht162x_dispdata [15] & 0x10) | bars;
653 ht162x_dispdata_notify (15, 15);
656 #define LCDSYM_NETWORK 14
657 #define LCDSYM_HANDSET 13
658 #define LCDSYM_SPEAKER 11
659 #define LCDSYM_FORWARD 10
660 #define LCDSYM_CLOCK 8
661 #define LCDSYM_LOCK 7
662 #define LCDSYM_BINARY 15
665 #define LCDSYM_HOUR10 0
666 #define LCDSYM_HMSEP 1
669 #define LCDSYM_DOT12 12
670 #define LCDSYM_DOT9 9
671 #define LCDSYM_DOT6 6
673 /* Special flag setting on the LCD, to flag conditions */
674 void ht162x_led_set (uint8_t lcdidx, led_colour_t col, bool notify) {
676 ht162x_dispdata [lcdidx] |= 0x10;
678 ht162x_dispdata [lcdidx] &= ~0x10;
681 ht162x_dispdata_notify (lcdidx, lcdidx);
686 /******** BOTTOM FUNCTIONS FOR LEDS AND BUTTONS ********/
689 /* Bottom-half operations to manipulate LED states */
690 void bottom_led_set (led_idx_t ledidx, led_colour_t col) {
692 case LED_IDX_HANDSET:
693 ht162x_led_set (13, col, true);
695 case LED_IDX_SPEAKERPHONE:
696 ht162x_led_set (11, col, true);
698 case LED_IDX_MESSAGE:
705 case LED_IDX_BACKLIGHT:
706 // Set bit DXSTAT=5 in PCR=0x2812 to 1/0
708 PCR0 |= 1 << REGBIT_PCR_DXSTAT ;
710 PCR0 &= ~ ( 1 << REGBIT_PCR_DXSTAT );
719 /* See if the phone (actually, the horn) is offhook */
720 bool bottom_phone_is_offhook (void) {
721 // The hook switch is attached to GPIO pin 5
722 return (IODATA & 0x20) != 0;
726 /* Scan to see if the top_hook_update() function must be called */
727 #if !defined NEED_HOOK_SCANNER_WHEN_ONHOOK || !defined NEED_HOOK_SCANNER_WHEN_OFFHOOK
728 # error "The BT200 does not generate an interrupt on hook contact changes"
730 static bool bt200_offhook = false;
731 void bottom_hook_scan (void) {
732 if (bt200_offhook != bottom_phone_is_offhook ()) {
733 bt200_offhook = !bt200_offhook;
734 top_hook_update (bt200_offhook);
738 /* Scan to see if the top_button_press() or top_button_release()
739 * functions must be called.
741 * The following bits are written to activate one or more keyboard rows:
742 * D0..D4 are sent to the variable "kbdisp" which has the proper address.
743 * The intermediate variable "kbdisp_outbuf" stores a copy of the bits,
744 * and is shared with the LCD routines so unused bits must be retained.
746 * The following bits of McBSP0 are read from PCR0 as keyboard columns:
747 * C0=CLKRP, C1=CLKXP, C2=FSRP, C3=FSXP, C4=DRSTAT
749 * The following routine is designed from the assumption that the keyboard
750 * is operated a single key at a time; if not, then any response could be
751 * valid. Note that we do not suppress multiple keys by sending an error
752 * code, or behaving like with key release.
754 #if !defined NEED_KBD_SCANNER_BETWEEN_KEYS || !defined NEED_KBD_SCANNER_DURING_KEYPRESS
755 # error "The BT200 does not generate an interrupt on key changes"
757 #define KBD_COLUMNS_MASK ( REGVAL_PCR_CLKRP | REGVAL_PCR_CLKXP | REGVAL_PCR_FSRP | REGVAL_PCR_FSXP | REGVAL_PCR_DRSTAT )
758 static bool bt200_kbd_pressed = false;
759 static const buttoncode_t keynum2code [25] = {
760 '1', '2', '3', HAVE_BUTTON_MESSAGE, HAVE_BUTTON_HOLD,
761 '4', '5', '6', HAVE_BUTTON_TRANSFER, HAVE_BUTTON_CONFERENCE,
762 '7', '8', '9', HAVE_BUTTON_FLASH, HAVE_BUTTON_MUTE,
763 '*', '0', '#', HAVE_BUTTON_SEND, HAVE_BUTTON_SPEAKER,
764 HAVE_BUTTON_DOWN, HAVE_BUTTON_UP, HAVE_BUTTON_CALLERS, HAVE_BUTTON_CALLED, HAVE_BUTTON_MENU
766 void bottom_keyboard_scan (void) {
768 scan = PCR0 & KBD_COLUMNS_MASK;
769 if (bt200_kbd_pressed) {
770 // Respond if the key is released
771 if (scan == KBD_COLUMNS_MASK) {
772 bt200_kbd_pressed = false;
773 kbdisp_outbuf &= 0xe0e0; // Make D0..D4 low
774 kbdisp = kbdisp_outbuf;
775 top_button_release ();
778 // Respond if a key is being pressed
779 if (scan != KBD_COLUMNS_MASK) {
781 for (row = 0; row < 5; row++) {
782 kbdisp_outbuf |= 0x1f1f; // Make D0..D4 high
783 kbdisp_outbuf &= ~(0x0101 << row); // Set D$row low
784 kbdisp = kbdisp_outbuf;
785 { volatile int pause = 5; while (pause > 0) pause--; }
786 scan = PCR0 & KBD_COLUMNS_MASK;
787 if (scan != KBD_COLUMNS_MASK) {
789 for (col = 0; col < 5; col++) {
790 if (! (scan & (0x01 << col))) {
791 uint16_t keynum = row * 5 + col;
792 buttonclass_t bcl = ((row <= 3) && (col <= 2))? BUTCLS_DTMF: BUTCLS_FIXED_FUNCTION;
793 buttoncode_t cde = keynum2code [keynum];
794 bt200_kbd_pressed = true;
795 top_button_press (bcl, cde);
801 // Failed, usually due to an I/O glitch
802 kbdisp_outbuf &= 0xe0e0; // Make D0..D4 low
803 kbdisp = kbdisp_outbuf;
809 /******** BOTTOM FUNCTIONS FOR FORMATTING / PRINTING INFORMATION ********/
812 /* Send an elapsed period (not a wallclock time) to the display.
813 * For BT200, this is shown in the top digits as MM:SS or as HH:MM.
814 * Note that there are 2 positions, and the first digit can only show a 1.
816 static app_level_t bt200_period_level = APP_LEVEL_ZERO;
817 void bottom_show_period (app_level_t level, uint8_t h, uint8_t m, uint8_t s) {
818 if (bt200_period_level > level) {
819 // Ignore those lower values, as this is highly time-dependent
822 bt200_period_level = level;
823 if ((h == 0) && (m <= 19)) {
827 ht162x_led_set (2, false, false); // "AM" off
828 ht162x_led_set (3, false, false); // "PM" off
829 ht162x_led_set (1, true, false); // ":" in "xx:xx"
830 ht162x_led_set (0, h >= 10, false); // "1" in "1x:xx"
831 ht162x_putchar (0, (h % 10) + '0', false);
832 ht162x_putchar (1, (m / 10) + '0', false);
833 ht162x_putchar (2, (m % 10) + '0', false);
834 ht162x_dispdata_notify (0, 3);
837 /* The level of the main portion of the display, along with an array
838 * with the contents at each level
840 static bt200_displine_level = APP_LEVEL_ZERO;
841 static bool bt200_level_active [APP_LEVEL_COUNT];
842 static uint8_t bt200_level_maintext [APP_LEVEL_COUNT] [12];
843 static uint8_t bt200_level_dotbits [APP_LEVEL_COUNT];
845 /* Internal routine to move a display level to the display.
846 * Note that no "led" style bits other than the dots in the main
847 * line are influenced.
849 static void bt200_displine_showlevel (app_level_t level) {
851 for (i = 0; i < 12; i++) {
852 ht162x_putchar (14 - i, bt200_level_maintext [level] [i], false);
854 ht162x_led_set (12, (bt200_level_dotbits [level] & 0x01), false);
855 ht162x_led_set ( 9, (bt200_level_dotbits [level] & 0x02), false);
856 ht162x_led_set ( 6, (bt200_level_dotbits [level] & 0x04), false);
857 ht162x_dispdata_notify (3, 14);
860 /* Internal routine to send a string to the display, either with or
861 * without setting the various dots. The dots are coded in bits
862 * 0, 1 and 2 of the dotbits parameter, from left to right.
864 static void bt200_display_showtxt (app_level_t level, char *txt, uint8_t dotbits) {
865 // 1. Print text to the proper level
867 while ((idx < 12) && *txt) {
868 bt200_level_maintext [level] [idx++] = *txt++;
871 bt200_level_maintext [level] [idx++] = ' ';
873 bt200_level_dotbits [level] = dotbits;
874 bt200_level_active [level] = true;
875 // 2. If the level is not exceeded by the current, reveal it
876 if (bt200_displine_level <= level) {
877 bt200_displine_showlevel (level);
878 bt200_displine_level = level;
883 /* Stop displaying content at the specified level. In some cases, older
884 * content may now pop up, in others the display could get cleared.
886 void bottom_show_close_level (app_level_t level) {
887 if (bt200_period_level == level) {
888 bt200_period_level = APP_LEVEL_ZERO;
889 ht162x_led_set (0, false, false);
890 ht162x_led_set (1, false, false);
891 ht162x_dispdata [0] = 0x00;
892 ht162x_dispdata [1] = 0x00;
893 ht162x_dispdata [2] = 0x00;
894 ht162x_dispdata_notify (0, 2);
896 if (bt200_displine_level == level) {
897 bt200_level_active [level] = false;
898 memset (bt200_level_maintext [level], ' ', 12);
899 while ((bt200_displine_level > APP_LEVEL_ZERO)
900 && !bt200_level_active [bt200_displine_level]) {
901 bt200_displine_level--;
903 bt200_displine_showlevel (bt200_displine_level);
907 /* Print an IPv4 address on the display */
908 void bottom_show_ip4 (app_level_t level, uint8_t bytes [4]) {
912 for (idx = 0; idx < 4; idx++) {
913 *ipptr++ = '0' + (bytes [idx] / 100);
914 *ipptr++ = '0' + ((bytes [idx] % 100) / 10);
915 *ipptr++ = '0' + (bytes [idx] % 10);
917 bt200_display_showtxt (level, ip, 0x07);
920 /* Print an IPv6 address, as far as this is possible, on the display
921 * - Remove the prefix /64 as it is widely known
922 * -TODO- If middle word is 0xfffe, remove it, display the rest, set dot #2
923 * -TODO- If first word is 0x0000, remove it, display the rest, set dot #1
924 * -TODO- If last word is 0x0001, remove it, display the rest, set dot #3
925 * - If nothing else is possible, use 6 bits per digit, dots and last digit blanc
926 void bottom_show_ip6 (app_level_t level, uint16_t words [8]) {
927 // TODO: Extra cases; for now, just dump 6 bits per 7-segment display
932 ht162x_led_set (12, 0, false);
933 ht162x_led_set ( 9, 0, false);
934 ht162x_led_set ( 6, 0, false);
935 for (idxo = 14; idxo >= 3; idxo--) {
936 ht162x_dispdata [idxo] &= 0x10;
943 uint8_t twobits = (words [idxi] >> shfi) & 0x03;
945 if (twobits & 0x10) {
946 twobits += 0x80 - 0x10; // bit 7 replaces bit 4
948 ht162x_dispdata [idxo] |= (twobits << shfo);
962 ht162x_dispdata_notify (14, 3);
965 /* A list of fixed messages, matching the fixed_msg_t values */
967 static char *bt200_fixed_messages [FIXMSG_COUNT] = {
977 /* Print a fixed message on the main line of the display */
978 void bottom_show_fixed_msg (app_level_t level, fixed_msg_t msg) {
979 if (msg < FIXMSG_COUNT) {
980 bt200_display_showtxt (level, bt200_fixed_messages [msg], 0x00);
984 /* Print a notification of the number of new / old voicemails */
985 void bottom_show_voicemail (app_level_t level, uint16_t new, uint16_t old) {
990 memcpy (msg, "xxx messages", 12);
992 msg [1] = (new % 100) / 10;
994 bt200_display_showtxt (level, msg, 0x00);
997 /******** BOTTOM LEVEL MAIN PROGRAM ********/
999 /* Setup the connectivity of the TIC55x as used on Grandstream BT20x */
1002 led_colour_t led = LED_STABLE_ON;
1004 // PLL setup: Crystal is 16.384 MHz, increase that 15x
1005 // 1. Switch to bypass mode by setting the PLLEN bit to 0.
1006 PLLCSR &= ~REGVAL_PLLCSR_PLLEN;
1007 // 2. Set the PLL to its reset state by setting the PLLRST bit to 1.
1008 PLLCSR |= REGVAL_PLLCSR_PLLRST;
1009 // 3. Change the PLL setting through the PLLM and PLLDIV0 bits.
1010 PLLM = REGVAL_PLLM_TIMES_15;
1011 PLLDIV0 = REGVAL_PLLDIVx_DxEN | REGVAL_PLLDIVx_PLLDIVx_1;
1012 // 4. Wait for 1 µs.
1013 { int ctr = 1000; while (ctr--) ; }
1014 // 5. Release the PLL from its reset state by setting PLLRST to 0.
1015 PLLCSR &= ~REGVAL_PLLCSR_PLLRST;
1016 // 6. Wait for the PLL to relock by polling the LOCK bit or by setting up a LOCK interrupt.
1017 while ((PLLCSR & REGVAL_PLLCSR_LOCK) == 0) {
1020 // 7. Switch back to PLL mode by setting the PLLEN bit to 1.
1021 PLLCSR |= REGVAL_PLLCSR_PLLEN;
1022 PLLDIV1 = REGVAL_PLLDIVx_DxEN | REGVAL_PLLDIVx_PLLDIVx_2;
1023 PLLDIV2 = REGVAL_PLLDIVx_DxEN | REGVAL_PLLDIVx_PLLDIVx_4;
1024 PLLDIV3 = REGVAL_PLLDIVx_DxEN | REGVAL_PLLDIVx_PLLDIVx_4;
1025 //TODO// PLLDIV3 = REGVAL_PLLDIVx_DxEN | REGVAL_PLLDIVx_PLLDIVx_2;
1026 //TODO// PLLCSR |= REGVAL_PLLCSR_PLLEN;
1028 // CPU clock is 245.76 MHz
1029 // SYSCLK1 is 122.88 MHz
1030 // SYSCLK2 is 61.44 MHz
1032 // EMIF settings, see SPRU621F, section 2.12 on "EMIF Registers"
1035 // EGCR2 = 0x0009; // ECLKOUT2-DIV-4
1036 // EGCR2 = 0x0001; //ECLKOUT2-DIV-1//
1037 EGCR2 = 0x0005; //ECLKOUT2-DIV-2//
1038 // EGCR1 = ...; // (defaults)
1039 // EGCR2 = ...; // (defaults)
1040 // CESCR1 = ...; // (defaults)
1041 // CESCR2 = ...; // (defaults)
1043 // CE0 selects the network interface
1044 // CE0_1 = 0xff03; // DEFAULT 8-bit async (and defaults)
1045 // Fail: CE0_1 = 0xc112; // 16-bit async, rd setup 2, rd strobe 1, rd hold 2
1046 // Fail: CE0_2 = 0x20a2; // wr setup 2, wr strobe 2, wr hold 2, rd setup 2
1049 // CE0_2 = ...; // (defaults)
1050 // CE0_SC1 = ...; // (defaults)
1051 // CE0_SC2 = ...; // (defaults)
1053 // CE1 selects the flash chip
1054 //WORKED?// CE1_1 = 0xff13; // 16-bit async (and defaults)
1057 // CE1_2 = ...; // (defaults)
1058 // CE1_SC1 = ...; // (defaults)
1059 // CE1_SC2 = ...; // (defaults)
1061 // CE2 selects the SDRAM chips
1062 //WORKS?// CE2_1 = 0xff33; // 32-bit SDRAM (and defaults)
1064 //TEST// CE2_1 = 0xff13; // 16-bit async (and defaults)
1065 // CE2_2 = ...; // (defaults)
1066 // CE2_SC1 = ...; // (defaults)
1067 // CE2_SC2 = ...; // (defaults)
1068 // Possible: SDC1, SDC2, SDRC1, SDRC2, SDX1, SDX2
1076 // CE3 selects the D-flipflops for keyboard and LCD
1077 CE3_1 = 0xff13; // 16-bit async (and defaults)
1078 //BT200ORIG// CE3_1 = 0x0220;
1079 //BT200ORIG// CE3_2 = 0x0270;
1080 // CE3_2 = ...; // (defaults)
1081 // CE3_SC1 = ...; // (defaults)
1082 // CE3_SC2 = ...; // (defaults)
1084 // Setup output ports; reset TLV chip; reset message levels
1085 { uint32_t ctr = 10000; while (ctr-- > 0) ; }
1086 IODIR |= (1 << 7) | (1 << 1);
1087 IODATA = (1 << 1); // Updated below small delay
1088 { uint32_t ctr; for (ctr=0; ctr < 7 * (600 / 12); ctr++) /* Wait 7x MCLK */ ; }
1089 IODATA |= (1 << 7) | (1 << 1); // See above small delay
1090 { uint32_t ctr; for (ctr=0; ctr < 132 * (600 / 12); ctr++) /* Wait at least 132 MCLK cycles */ ; }
1092 // Setup McBSP1 for linking to TLV320AIC20K
1093 // Generate a CLKG at 12.288 MHz, and FS at 8 kHz
1094 // following the procedure of spru592e section 3.5
1097 SPCR1_1 = 0x0000; // Disable/reset receiver, required in spru592e
1098 SPCR2_1 = 0x0000; // Disable/reset sample rate generator
1099 SRGR1_1 = REGVAL_SRGR1_FWID_1 | REGVAL_SRGR1_CLKGDIV_4;
1100 SRGR2_1 = REGVAL_SRGR2_CLKSM | REGVAL_SRGR2_FSGM | REGVAL_SRGR2_FPER_1535;
1101 //COPIED_BELOW// PCR1 = /*TODO: (1 << REGBIT_PCR_IDLEEN) | */ (1 << REGBIT_PCR_FSXM) /* | (1 << REGBIT_PCR_FSRM) */ | (1 << REGBIT_PCR_CLKXM) /* | (1 << REGBIT_PCR_CLKRM) */ | (1 << REGBIT_PCR_CLKXP) | (1 << REGBIT_PCR_CLKRP);
1102 PCR1 = (1 << REGBIT_PCR_FSXM) | (1 << REGBIT_PCR_CLKXM);
1103 { uint32_t ctr = 10000; while (ctr-- > 0) ; }
1104 // SPCR2_1 |= REGVAL_SPCR2_GRST_NOTRESET | REGVAL_SPCR2_FRST_NOTRESET;
1105 RCR1_1 = (0 << 8) | (2 << 5); // Read 1 frame of 16 bits per FS
1106 XCR1_1 = (0 << 8) | (2 << 5); // Write 1 frame of 16 bits per FS
1107 RCR2_1 = 0x0001; // Read with 1 clockcycle delay
1108 XCR2_1 = 0x0001; // Write with 1 clockcycle delay
1109 //TODO:NOT-SPI-BUT-CONTINUOUS-CLOCK// SPCR1_1 |= REGVAL_SPCR1_CLKSTP_NODELAY;
1111 // Setup I2C for communication with the TLV320AIC20K codec
1112 // Prescale SYSCLK2 down from 61.44 MHz to 10.24 MHz so it falls
1113 // in the required 7 Mhz to 12 MHz range; support a 100 kHz I2C bus
1114 // by setting low/high period to 51 such periods.
1115 // Note: The only peripheral TLV320AIC20K could go up to 900 kHz
1116 I2CMDR = REGVAL_I2CMDR_MST | /* reset to set PSC */ REGVAL_I2CMDR_FREE | REGVAL_I2CMDR_BC_8;
1118 I2CCLKH = 51 - 5; /* TODO: 900 kHz is possible on TLV320AIC20K */
1120 I2COAR = REGVAL_I2COAR;
1121 I2CMDR = REGVAL_I2CMDR_MST | REGVAL_I2CMDR_NORESET | REGVAL_I2CMDR_FREE | REGVAL_I2CMDR_BC_8;
1123 // Setup DMA channel 0 for playing from DSP to TLV320AIC2x
1124 // Setup DMA channel 1 for recording from TLV320AIC2x to DSP
1126 // Both channels have a block (their entire RAM buffer) comprising
1127 // of 25 frames, which each are 64 samples of 16 bits in size.
1128 // At 8 kHz sample rate, frames cause 125 interrupts per second;
1129 // at 48 kHz this rises to 750 (per channel), still comfortable.
1130 // The total buffer is 1600 samples of 16 bits long. Each time a
1131 // frame send finishes, an interrupt checks if there is another
1132 // frame of 64 samples ready to go; if not, it will disable the
1133 // DMA channel. Hint routines serve to restart DMA after that.
1134 // Conversely, the DMA interrupt handlers can make top-calls to
1135 // indicate that data is ready for reading or that space is
1136 // available for writing.
1137 // The settings below prepare DMA for continuous playing and
1138 // recording, but with the setup disabled until hinted.
1140 DMAGCR = REGVAL_DMAGCR_FREE;
1141 DMAGTCR = 0x00; // No timeout support
1142 DMACCR_0 = REGVAL_DMACCR_SRCAMODE_CONST | REGVAL_DMACCR_DSTAMODE_POSTINC | REGVAL_DMACCR_PRIO | REGVAL_DMACCR_SYNC_MCBSP1_REV | REGVAL_DMACCR_REPEAT | REGVAL_DMACCR_AUTOINIT;
1143 DMACCR_1 = REGVAL_DMACCR_SRCAMODE_POSTINC | REGVAL_DMACCR_DSTAMODE_CONST | REGVAL_DMACCR_PRIO | REGVAL_DMACCR_SYNC_MCBSP1_TEV | REGVAL_DMACCR_REPEAT | REGVAL_DMACCR_AUTOINIT;
1144 DMACICR_0 = REGVAL_DMACICR_FRAMEIE;
1145 DMACICR_1 = REGVAL_DMACICR_FRAMEIE;
1146 //TODO// DMACSDP_0 = REGVAL_DMACSDP_SRC_PERIPH | REGVAL_DMACSDP_DST_DARAM1 | REGVAL_DMACSDP_DATATYPE_16BIT;
1147 //TODO// DMACSDP_1 = REGVAL_DMACSDP_SRC_DARAM0 | REGVAL_DMACSDP_DST_PERIPH | REGVAL_DMACSDP_DATATYPE_16BIT;
1148 DMACSDP_0 = REGVAL_DMACSDP_SRC_PERIPH | REGVAL_DMACSDP_DST_EMIF | REGVAL_DMACSDP_DATATYPE_16BIT;
1149 DMACSDP_1 = REGVAL_DMACSDP_SRC_EMIF | REGVAL_DMACSDP_DST_PERIPH | REGVAL_DMACSDP_DATATYPE_16BIT;
1150 DMACSSAL_0 = ((intptr_t) &DRR1_1) << 1;
1151 DMACSSAU_0 = ((intptr_t) &DRR1_1) >> 15;
1152 DMACDSAL_0 = (uint16_t) (((intptr_t) samplebuf_record) << 1);
1153 DMACDSAU_0 = (uint16_t) (((intptr_t) samplebuf_record) >> 15);
1154 DMACSSAL_1 = (uint16_t) (((intptr_t) samplebuf_play) << 1);
1155 DMACSSAU_1 = (uint16_t) (((intptr_t) samplebuf_play) >> 15);
1156 DMACDSAL_1 = ((intptr_t) &DXR1_1) << 1;
1157 DMACDSAU_1 = ((intptr_t) &DXR1_1) >> 15;
1158 #if TRY_SOMETHING_ELSE_TO_GET_INTERRUPTS
1159 DMACEN_0 = 64; /* 64 elements (samples) per frame (continue-checks) */
1161 DMACFN_0 = (BUFSZ / 64); /* 25 frames (continue-checks) per block (buffer) */
1162 DMACFN_1 = (BUFSZ / 64);
1171 // Further initiation follows
1173 asm (" bclr xf"); // Switch off MESSAGE LED
1174 { uint16_t ctr = 250; while (ctr > 0) { ctr--; } }
1175 bottom_critical_region_begin (); // _disable_interrupts ();
1176 IER0 = IER1 = 0x0000;
1177 tic55x_setup_timers ();
1178 tic55x_setup_interrupts ();
1179 ht162x_setup_lcd ();
1180 tlv320aic2x_set_samplerate (0, 8000);
1181 tlv320aic2x_setup_sound ();
1182 ksz8842_setup_network ();
1183 // Enable INT0..INT3
1184 //TODO:TEST// IER0 |= 0x0a0c;
1185 //TODO:TEST// IER1 |= 0x0005;
1186 IER0 |= (1 << REGBIT_IER0_DMAC1) | (1 << REGBIT_IER0_INT0) | (1 << REGBIT_IER0_TINT0); // 0x0214;
1187 IER1 |= (1 << REGBIT_IER1_DMAC0); // 0x0004;
1188 PCR0 = (1 << REGBIT_PCR_XIOEN) | (1 << REGBIT_PCR_RIOEN);
1190 for (idx = 0; idx < APP_LEVEL_COUNT; idx++) {
1191 bt200_level_active [idx] = false;
1194 {uint8_t idx, dig, bar;
1195 idx=0; dig=0; bar=0;
1196 memset (ht162x_dispdata, 0x00, sizeof (ht162x_dispdata));
1199 ht162x_putchar (14 - idx, (dig < 10)? (dig + '0'): (dig + 'A' - 11));
1200 ht162x_audiolevel ((bar < 8)? (bar << 5): ((14-bar) << 5));
1201 // bottom_led_set (LED_IDX_MESSAGE, LED_STABLE_OFF);
1202 ht162x_dispdata_notify (14 - idx, 14 - idx);
1203 ht162x_dispdata_notify (15, 15);
1204 // bottom_led_set (LED_IDX_MESSAGE, LED_STABLE_ON );
1205 idx = (idx + 1) % 12;
1206 dig = (dig + 1) % 38;
1207 bar = (bar + 1) % 14;
1208 ctr = 650000; while (ctr>0) ctr--;
1213 //TODO// IER0 = 0xdefc;
1214 //TODO// IER1 = 0x00ff;
1215 /* TODO: Iterate over flash partitions that can boot, running each in turn: */