/* * Copyright (c) 2010, Mariano Alvira and other contributors * to the MC1322x project (http://mc1322x.devl.org) * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the Institute nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * This file is part of libmc1322x: see http://mc1322x.devl.org * for details. * * */ #include #include #ifndef DEBUG_MACA #define DEBUG_MACA 0 #endif #if (DEBUG_MACA == 0) #define PRINTF(...) #else #define PRINTF(...) printf(__VA_ARGS__) #endif #ifndef MACA_BOUND_CHECK #define MACA_BOUND_CHECK 0 #endif #if (MACA_BOUND_CHECK == 0) #define BOUND_CHECK(x) #else #define BOUND_CHECK(x) bound_check(x) #endif #ifndef NUM_PACKETS #define NUM_PACKETS 32 #endif /* for 250kHz clock */ #define MACA_CLOCK_DIV 95 /* (32 chips/sym) * (sym/4bits) * (8bits/byte) = (64 chips/byte) */ /* (8 chips/clk) * (byte/64 chips) = byte/8clks */ #define CLK_PER_BYTE 8 #ifndef RECV_SOFTIMEOUT #define RECV_SOFTIMEOUT (1024*128*CLK_PER_BYTE) #endif #ifndef CPL_TIMEOUT #define CPL_TIMEOUT (2*128*CLK_PER_BYTE) #endif #ifndef MACA_INSERT_ACK #define MACA_INSERT_ACK 1 #endif /* Bit in first byte of 802.15.4 message that indicates an */ /* acknowledgereply frame is expected */ #define MAC_ACK_REQUEST_FLAG 0x20 #define reg(x) (*(volatile uint32_t *)(x)) int count_packets(void); void Print_Packets(char *s); static volatile packet_t packet_pool[NUM_PACKETS]; static volatile packet_t *free_head, *rx_end, *tx_end, *dma_tx, *dma_rx; /* rx_head and tx_head are visible to the outside */ /* so you can peek at it and see if there is data */ /* waiting for you, or data still to be sent */ volatile packet_t *rx_head, *tx_head; /* used for ack recpetion if the packet_pool goes empty */ /* doesn't go back into the pool when freed */ static volatile packet_t dummy_ack; static volatile packet_t dummy_rx; /* incremented on every maca entry */ /* you can use this to detect that the receive loop is still running */ volatile uint32_t maca_entry = 0; enum posts { NO_POST = 0, TX_POST, RX_POST, MAX_POST, }; static volatile uint8_t last_post = NO_POST; /* maca_pwr indicates whether the radio is on or off */ /* Test it before accessing any radio function or the CPU may hang */ volatile uint8_t maca_pwr = 0; volatile uint8_t fcs_mode = USE_FCS; volatile uint8_t prm_mode = PROMISC; /* call periodically to */ /* check that maca_entry is changing */ /* if it is not, it will do a manual call to maca_isr which should */ /* get the ball rolling again */ /* also checks that the clock is running --- if it isn't then */ /* it calls redoes the maca intialization but _DOES NOT_ free all packets */ void check_maca(void) { safe_irq_disable(MACA); static volatile uint32_t last_time; static volatile uint32_t last_entry; volatile uint32_t i; #if DEBUG_MACA volatile uint32_t count; #endif /* if *MACA_CLK == last_time */ /* try waiting for one clock period */ /* since maybe check_maca is getting called quickly */ for(i=0; (i < 1024) && (*MACA_CLK == last_time); i++) { continue; } if(*MACA_CLK == last_time) { PRINTF("check maca: maca_clk stopped, restarting\n"); /* clock isn't running */ ResumeMACASync(); *INTFRC = (1< (*MACA_SFTCLK + RECV_SOFTIMEOUT)) && (last_time > (*MACA_CPLCLK + CPL_TIMEOUT))) { PRINTF("check maca: complete clocks expired\n"); /* all complete clocks have expired */ /* check that maca entry is changing */ /* if not, do call the isr to restart the cycle */ if(last_entry == maca_entry) { PRINTF("check maca: forcing isr\n"); *INTFRC = (1<left; printf("->0x%lx", (uint32_t) p); } printf("\n\r"); p = tx_head; printf("tx_head: 0x%lx ", (uint32_t) tx_head); while(p != 0) { p = p->left; printf("->0x%lx", (uint32_t) p); } printf("\n\r"); p = rx_head; printf("rx_head: 0x%lx ", (uint32_t) rx_head); while(p != 0) { p = p->left; printf("->0x%lx", (uint32_t) p); } printf("\n\r"); printf("dma_rx: 0x%lx\n", (uint32_t) dma_rx); printf("dma_tx: 0x%lx\n", (uint32_t) dma_tx); } inline void bad_packet_bounds(void) { PRINTF("bad packet bounds! Halting.\n"); while(1) { continue; } } int count_packets(void) { volatile int8_t total = -1; #if PACKET_STATS volatile packet_t *pk; volatile uint8_t tx, rx, free; volatile int i; for(i = 0; i < NUM_PACKETS; i++) { packet_pool[i].seen = 0; } pk = tx_head; tx = 0; while( pk != 0 ) { if(pk->seen == 0) { tx++; } pk->seen++; pk = pk->left; } pk = rx_head; rx = 0; while( pk != 0 ) { if(pk->seen == 0) { rx++; } pk->seen++; pk = pk->left; } pk = free_head; free = 0; while( pk != 0 ) { if(pk->seen == 0) { free++; } pk->seen++; pk = pk->left; } total = free + rx + tx; if(dma_rx && (dma_rx->seen == 0)) { dma_rx->seen++; total++; } if(dma_tx && (dma_tx->seen == 0)) { dma_tx->seen++; total++; } #endif /* PACKET_STATS */ return total; } void bound_check(volatile packet_t *p) { volatile int i; if((p == 0) || (p == &dummy_ack)) { return; } for(i=0; i < NUM_PACKETS; i++) { if(p == &packet_pool[i]) { return; } } bad_packet_bounds(); } /* public packet routines */ /* heads are to the right */ /* ends are to the left */ void maca_free_packet(volatile packet_t *p) { safe_irq_disable(MACA); BOUND_CHECK(p); if(!p) { PRINTF("free_packet passed packet 0\n\r"); return; } if(p == &dummy_ack) { return; } BOUND_CHECK(free_head); p->length = 0; p->offset = 0; p->left = free_head; p->right = 0; #if PACKET_STATS p->seen = 0; p->post_tx = 0; p->get_free = 0; p->rxd = 0; #endif free_head = p; BOUND_CHECK(free_head); irq_restore(); if(bit_is_set(*NIPEND, INT_NUM_MACA)) { *INTFRC = (1 << INT_NUM_MACA); } return; } volatile packet_t* get_free_packet(void) { volatile packet_t *p; safe_irq_disable(MACA); BOUND_CHECK(free_head); p = free_head; if( p != 0 ) { free_head = p->left; free_head->right = 0; } BOUND_CHECK(free_head); #if PACKET_STATS p->get_free++; #endif // print_packets("get_free_packet"); irq_restore(); if(bit_is_set(*NIPEND, INT_NUM_MACA)) { *INTFRC = (1 << INT_NUM_MACA); } return p; } void post_receive(void) { last_post = RX_POST; /* this sets the rxlen field */ /* this is undocumented but very important */ /* you will not receive anything without setting it */ *MACA_TXLEN = (MAX_PACKET_SIZE << 16); if(dma_rx == 0) { dma_rx = get_free_packet(); if (dma_rx == 0) { PRINTF("trying to fill MACA_DMARX in post_receieve but out of packet buffers\n\r"); dma_rx = &dummy_rx; /* set the sftclock so that we return to the maca_isr */ *MACA_SFTCLK = *MACA_CLK + RECV_SOFTIMEOUT; /* soft timeout */ *MACA_TMREN = (1 << maca_tmren_sft); /* no free buffers, so don't start a reception */ enable_irq(MACA); return; } } BOUND_CHECK(dma_rx); BOUND_CHECK(dma_tx); *MACA_DMARX = (uint32_t)&(dma_rx->data[0]); /* with timeout */ *MACA_SFTCLK = *MACA_CLK + RECV_SOFTIMEOUT; /* soft timeout */ *MACA_TMREN = (1 << maca_tmren_sft); /* start the receive sequence */ *MACA_CONTROL = ( (1 << maca_ctrl_asap) | ( 4 << PRECOUNT) | ( fcs_mode << NOFC ) | ( prm_mode << PRM) | #if 0 //dak says removing ctrl auto fixes the autoack checksum error --- doesn't cause a performance issue either (1 << maca_ctrl_auto) | #endif (maca_ctrl_seq_rx)); /* status bit 10 is set immediately */ /* then 11, 10, and 9 get set */ /* they are cleared once we get back to maca_isr */ } volatile packet_t* rx_packet(void) { volatile packet_t *p; safe_irq_disable(MACA); BOUND_CHECK(rx_head); p = rx_head; if( p != 0 ) { rx_head = p->left; rx_head->right = 0; } #if PACKET_STATS p->rxd++; #endif // print_packets("rx_packet"); irq_restore(); if(bit_is_set(*NIPEND, INT_NUM_MACA)) { *INTFRC = (1 << INT_NUM_MACA); } return p; } void post_tx(void) { /* set dma tx pointer to the payload */ /* and set the tx len */ disable_irq(MACA); last_post = TX_POST; dma_tx = tx_head; #if PACKET_STATS dma_tx->post_tx++; #endif *MACA_TXSEQNR = dma_tx->data[2]; *MACA_TXLEN = (uint32_t)((dma_tx->length) + 2) | (3 << 16); /* set rx len to ACK length */ *MACA_DMATX = (uint32_t)&(dma_tx->data[ 0 + dma_tx->offset]); if(dma_rx == 0) { dma_rx = get_free_packet(); if (dma_rx == 0) { dma_rx = &dummy_ack; PRINTF("trying to fill MACA_DMARX on post_tx but out of packet buffers\n\r"); } } BOUND_CHECK(dma_rx); BOUND_CHECK(dma_tx); *MACA_DMARX = (uint32_t)&(dma_rx->data[0]); /* disable soft timeout clock */ /* disable start clock */ *MACA_TMRDIS = (1 << maca_tmren_sft) | ( 1<< maca_tmren_cpl) | ( 1 << maca_tmren_strt ) ; /* set complete clock to long value */ /* acts like a watchdog in case the MACA locks up */ *MACA_CPLCLK = *MACA_CLK + CPL_TIMEOUT; /* enable complete clock */ *MACA_TMREN = (1 << maca_tmren_cpl); enable_irq(MACA); *MACA_CONTROL = ( ( 4 << PRECOUNT) | ( prm_mode << PRM) | (maca_ctrl_mode_no_cca << maca_ctrl_mode) | (1 << maca_ctrl_asap) | (maca_ctrl_seq_tx)); /* status bit 10 is set immediately */ /* then 11, 10, and 9 get set */ /* they are cleared once we get back to maca_isr */ } void tx_packet(volatile packet_t *p) { safe_irq_disable(MACA); BOUND_CHECK(p); if(!p) { PRINTF("tx_packet passed packet 0\n\r"); return; } if(tx_head == 0) { /* start a new queue if empty */ tx_end = p; tx_end->left = 0; tx_end->right = 0; tx_head = tx_end; } else { /* add p to the end of the queue */ tx_end->left = p; p->right = tx_end; /* move the queue */ tx_end = p; tx_end->left = 0; } // print_packets("tx packet"); irq_restore(); if(bit_is_set(*NIPEND, INT_NUM_MACA)) { *INTFRC = (1 << INT_NUM_MACA); } if(last_post == NO_POST) { *INTFRC = (1<left; if(tx_head == 0) { tx_end = 0; } maca_free_packet(p); // print_packets("free tx head"); irq_restore(); if(bit_is_set(*NIPEND, INT_NUM_MACA)) { *INTFRC = (1 << INT_NUM_MACA); } return; } void add_to_rx(volatile packet_t *p) { safe_irq_disable(MACA); BOUND_CHECK(p); if(!p) { PRINTF("add_to_rx passed packet 0\n\r"); return; } p->offset = 1; /* first byte is the length */ if(rx_head == 0) { /* start a new queue if empty */ rx_end = p; rx_end->left = 0; rx_end->right = 0; rx_head = rx_end; } else { rx_end->left = p; p->right = rx_end; rx_end = p; rx_end->left = 0; } // print_packets("add to rx"); irq_restore(); if(bit_is_set(*NIPEND, INT_NUM_MACA)) { *INTFRC = (1 << INT_NUM_MACA); } return; } void insert_at_rx_head(volatile packet_t *p) { safe_irq_disable(MACA); BOUND_CHECK(p); if(!p) { PRINTF("insert_at_rx_head passed packet 0\n\r"); return; } p->offset = 1; /* first byte is the length */ if(rx_head == 0) { /* start a new queue if empty */ rx_end = p; rx_end->left = 0; rx_end->right = 0; rx_head = rx_end; } else { rx_head->right = p; p->left = rx_head; p->right = 0; rx_head = p; } // print_packets("insert at rx head"); irq_restore(); if(bit_is_set(*NIPEND, INT_NUM_MACA)) { *INTFRC = (1 << INT_NUM_MACA); } return; } void decode_status(void) { volatile uint32_t code; code = get_field(*MACA_STATUS,CODE); /* PRINTF("status code 0x%x\n\r",code); */ switch(code) { case ABORTED: { PRINTF("maca: aborted\n\r"); ResumeMACASync(); break; } case NOT_COMPLETED: { PRINTF("maca: not completed\n\r"); ResumeMACASync(); break; } case CODE_TIMEOUT: { PRINTF("maca: timeout\n\r"); ResumeMACASync(); break; } case NO_ACK: { PRINTF("maca: no ack\n\r"); ResumeMACASync(); break; } case EXT_TIMEOUT: { PRINTF("maca: ext timeout\n\r"); ResumeMACASync(); break; } case EXT_PND_TIMEOUT: { PRINTF("maca: ext pnd timeout\n\r"); ResumeMACASync(); break; } case SUCCESS: { //PRINTF("maca: success\n\r"); ResumeMACASync(); break; } default: { PRINTF("status: %x", (unsigned int)*MACA_STATUS); ResumeMACASync(); } } } void maca_isr(void) { // print_packets("maca_isr"); maca_entry++; if (bit_is_set(*MACA_STATUS, maca_status_ovr)) { PRINTF("maca overrun\n\r"); } if (bit_is_set(*MACA_STATUS, maca_status_busy)) { PRINTF("maca busy\n\r"); } if (bit_is_set(*MACA_STATUS, maca_status_crc)) { PRINTF("maca crc error\n\r"); } if (bit_is_set(*MACA_STATUS, maca_status_to)) { PRINTF("maca timeout\n\r"); } if (data_indication_irq()) { *MACA_CLRIRQ = (1 << maca_irq_di); if (dma_rx != &dummy_ack && dma_rx != &dummy_rx) { dma_rx->length = *MACA_GETRXLVL - 2; /* packet length does not include FCS */ dma_rx->lqi = get_lqi(); dma_rx->rx_time = *MACA_TIMESTAMP; /* check if received packet needs an ack */ if(prm_mode == AUTOACK && (dma_rx->data[1] & 0x20)) { /* this wait is necessary to auto-ack */ volatile uint32_t wait_clk; wait_clk = *MACA_CLK + 200; while(*MACA_CLK < wait_clk) { continue; } } if(maca_rx_callback != 0) { maca_rx_callback(dma_rx); } add_to_rx(dma_rx); } dma_rx = 0; } if (filter_failed_irq()) { PRINTF("maca filter failed\n\r"); ResumeMACASync(); *MACA_CLRIRQ = (1 << maca_irq_flt); } if (checksum_failed_irq()) { PRINTF("maca checksum failed\n\r"); ResumeMACASync(); *MACA_CLRIRQ = (1 << maca_irq_crc); } if (softclock_irq()) { *MACA_CLRIRQ = (1 << maca_irq_sftclk); } if (poll_irq()) { *MACA_CLRIRQ = (1 << maca_irq_poll); } if(action_complete_irq()) { /* PRINTF("maca action complete %d\n\r", get_field(*MACA_CONTROL,SEQUENCE)); */ if(last_post == TX_POST) { tx_head->status = get_field(*MACA_STATUS,CODE); #if MACA_INSERT_ACK /* Having sent a message with the acknowledge request flag set the * MACA hardware will only give a tx success indication if the message * was acknowledged by the remote node. We need to detect this * condition and inject an ACK packet into the internal receive stream * as the higher layers are expecting to see an ACK packet.*/ if(tx_head->status == SUCCESS && (tx_head->data[0] & MAC_ACK_REQUEST_FLAG)) { /* Create the dummy ack packet */ static volatile packet_t *ack_p; if(ack_p = get_free_packet()) { ack_p->length = 3; ack_p->offset = 1; ack_p->data[0] = 3; ack_p->data[1] = 0x02; ack_p->data[2] = 0; ack_p->data[3] = *MACA_TXSEQNR; insert_at_rx_head(ack_p); } } #endif if(maca_tx_callback != 0) { maca_tx_callback(tx_head); } dma_tx = 0; free_tx_head(); last_post = NO_POST; } ResumeMACASync(); *MACA_CLRIRQ = (1 << maca_irq_acpl); } decode_status(); if (*MACA_IRQ != 0) { PRINTF("*MACA_IRQ %x\n\r", (unsigned int)*MACA_IRQ); } if(tx_head != 0) { post_tx(); } else { post_receive(); } } static uint8_t ram_values[4]; void init_phy(void) { // *MACA_TMREN = (1 << maca_tmren_strt) | (1 << maca_tmren_cpl); *MACA_CLKDIV = MACA_CLOCK_DIV; *MACA_WARMUP = 0x00180012; *MACA_EOFDELAY = 0x00000004; *MACA_CCADELAY = 0x001a0022; *MACA_TXCCADELAY = 0x00000025; *MACA_FRAMESYNC0 = 0x000000A7; *MACA_CLK = 0x00000008; *MACA_RXACKDELAY = 30; *MACA_RXEND = 180; *MACA_TXACKDELAY = 68; *MACA_MASKIRQ = ((1 << maca_irq_rst) | (1 << maca_irq_acpl) | (1 << maca_irq_cm) | (1 << maca_irq_flt) | (1 << maca_irq_crc) | (1 << maca_irq_di) | (1 << maca_irq_sftclk) ); *MACA_SLOTOFFSET = 0x00350000; } void reset_maca(void) { volatile uint32_t cnt; *MACA_RESET = (1 << maca_reset_rst); for(cnt = 0; cnt < 100; cnt++) {}; *MACA_RESET = (1 << maca_reset_clkon); *MACA_CONTROL = maca_ctrl_seq_nop; for(cnt = 0; cnt < 400000; cnt++) {}; /* Clear all interrupts. */ *MACA_CLRIRQ = 0xffff; } /* 004030c4 : 4030c4: 4806 ldr r0, [pc, #24] (4030e0 ) // r0 gets base 0x80009a00 4030c6: 6881 ldr r1, [r0, #8] // r1 gets *(0x80009a08) 4030c8: 4806 ldr r0, [pc, #24] (4030e4 ) // r0 gets 0x0000f7df 4030ca: 4308 orrs r0, r1 // or them, r0 has it 4030cc: 4904 ldr r1, [pc, #16] (4030e0 ) // r1 gets base 0x80009a00 4030ce: 6088 str r0, [r1, #8] // put r0 into 0x80009a08 4030d0: 0008 lsls r0, r1, #0 // r0 gets r1, r0 is the base now 4030d2: 4905 ldr r1, [pc, #20] (4030e8 ) // r1 gets 0x00ffffff 4030d4: 60c1 str r1, [r0, #12] // put 0x00ffffff into base+12 4030d6: 0b09 lsrs r1, r1, #12 // r1 = 0x00ffffff >> 12 4030d8: 6101 str r1, [r0, #16] // put r1 base+16 4030da: 2110 movs r1, #16 // r1 gets 16 4030dc: 6001 str r1, [r0, #0] // put r1 in the base 4030de: 4770 bx lr // return 4030e0: 80009a00 .word 0x80009a00 4030e4: 0000f7df .word 0x0000f7df 4030e8: 00ffffff .word 0x00ffffff */ /* tested and is good */ #define RF_BASE 0x80009a00 void flyback_init(void) { uint32_t val8, or; val8 = *(volatile uint32_t *)(RF_BASE+8); or = val8 | 0x0000f7df; *(volatile uint32_t *)(RF_BASE+8) = or; *(volatile uint32_t *)(RF_BASE+12) = 0x00ffffff; *(volatile uint32_t *)(RF_BASE+16) = (((uint32_t)0x00ffffff)>>12); *(volatile uint32_t *)(RF_BASE) = 16; /* good luck and godspeed */ } #define MAX_SEQ1 2 const uint32_t addr_seq1[MAX_SEQ1] = { 0x80003048, 0x8000304c, }; const uint32_t data_seq1[MAX_SEQ1] = { 0x00000f78, 0x00607707, }; #define MAX_SEQ2 2 const uint32_t addr_seq2[MAX_SEQ2] = { 0x8000a050, 0x8000a054, }; const uint32_t data_seq2[MAX_SEQ2] = { 0x0000047b, 0x0000007b, }; #define MAX_CAL3_SEQ1 3 const uint32_t addr_cal3_seq1[MAX_CAL3_SEQ1] = { 0x80009400,0x80009a04,0x80009a00, }; const uint32_t data_cal3_seq1[MAX_CAL3_SEQ1] = {0x00020017,0x8185a0a4,0x8c900025, }; #define MAX_CAL3_SEQ2 2 const uint32_t addr_cal3_seq2[MAX_CAL3_SEQ2] = { 0x80009a00,0x80009a00,}; const uint32_t data_cal3_seq2[MAX_CAL3_SEQ2] = { 0x8c900021,0x8c900027,}; #define MAX_CAL3_SEQ3 1 const uint32_t addr_cal3_seq3[MAX_CAL3_SEQ3] = { 0x80009a00 }; const uint32_t data_cal3_seq3[MAX_CAL3_SEQ3] = { 0x8c900000 }; #define MAX_CAL5 4 const uint32_t addr_cal5[MAX_CAL5] = { 0x80009400, 0x8000a050, 0x8000a054, 0x80003048, }; const uint32_t data_cal5[MAX_CAL5] = { 0x00000017, 0x00000000, 0x00000000, 0x00000f00, }; #define MAX_DATA 43 const uint32_t addr_reg_rep[MAX_DATA] = { 0x80004118,0x80009204,0x80009208,0x8000920c,0x80009210,0x80009300,0x80009304,0x80009308,0x8000930c,0x80009310,0x80009314,0x80009318,0x80009380,0x80009384,0x80009388,0x8000938c,0x80009390,0x80009394,0x8000a008,0x8000a018,0x8000a01c,0x80009424,0x80009434,0x80009438,0x8000943c,0x80009440,0x80009444,0x80009448,0x8000944c,0x80009450,0x80009460,0x80009464,0x8000947c,0x800094e0,0x800094e4,0x800094e8,0x800094ec,0x800094f0,0x800094f4,0x800094f8,0x80009470,0x8000981c,0x80009828 }; const uint32_t data_reg_rep[MAX_DATA] = { 0x00180012,0x00000605,0x00000504,0x00001111,0x0fc40000,0x20046000,0x4005580c,0x40075801,0x4005d801,0x5a45d800,0x4a45d800,0x40044000,0x00106000,0x00083806,0x00093807,0x0009b804,0x000db800,0x00093802,0x00000015,0x00000002,0x0000000f,0x0000aaa0,0x01002020,0x016800fe,0x8e578248,0x000000dd,0x00000946,0x0000035a,0x00100010,0x00000515,0x00397feb,0x00180358,0x00000455,0x00000001,0x00020003,0x00040014,0x00240034,0x00440144,0x02440344,0x04440544,0x0ee7fc00,0x00000082,0x0000002a }; void maca_off(void) { /* Do nothing if already off */ if (maca_pwr == 0) return; /* wait here till complete and then go off */ while (last_post == TX_POST) { return; } disable_irq(MACA); maca_pwr = 0; /* Disable clocks, cancel possible delayed RX post */ /* Note mcu will hang if radio is off when a startclk post comes through */ *MACA_TMRDIS = (1 << maca_tmren_sft) | ( 1<< maca_tmren_cpl) | ( 1 << maca_tmren_strt); /* Turn off the radio regulators */ CRM->VREG_CNTLbits.VREG_1P8V_EN = 0; CRM->VREG_CNTLbits.VREG_1P5V_EN = 0; /* Hold the maca in reset */ maca_reset = maca_reset_rst; } void maca_on(void) { if (maca_pwr != 0) { return; } maca_pwr = 1; /* Turn the radio regulators back on */ CRM->VREG_CNTLbits.VREG_1P8V_EN = 1; CRM->VREG_CNTLbits.VREG_1P5V_EN = 3; while(CRM->STATUSbits.VREG_1P8V_RDY == 0) { continue; } while(CRM->STATUSbits.VREG_1P5V_RDY == 0) { continue; } /* Take out of reset */ *MACA_RESET = (1 << maca_reset_clkon); /* Wait for VREG_1P5V_RDY indication */ while (!((*(volatile uint32_t *)0x80003018) & (1<< 19))) {} /* If last turnoff had a pending RX post we will get an action complete/PLL unlock interrupt. * If an abort is now issued we will get an action complete/abort interrupt. * This action complete is delayed by some unknown amount, just clearing MACA_IRQ below will not stop it. * However a NOP does the job! */ *MACA_CONTROL = maca_ctrl_seq_nop | (1 << maca_ctrl_asap); /* Something is allowing reserved interrupt 13 on restart? */ *MACA_MASKIRQ = ((1 << maca_irq_rst) | (1 << maca_irq_acpl) | (1 << maca_irq_cm) | (1 << maca_irq_flt) | (1 << maca_irq_crc) | (1 << maca_irq_di) | (1 << maca_irq_sftclk) ); last_post = NO_POST; *MACA_CLRIRQ = 0xffff; enable_irq(MACA); *INTFRC = (1 << INT_NUM_MACA); } /* initialized with 0x4c */ uint8_t ctov[16] = { 0x0b, 0x0b, 0x0b, 0x0a, 0x0d, 0x0d, 0x0c, 0x0c, 0x0f, 0x0e, 0x0e, 0x0e, 0x11, 0x10, 0x10, 0x0f, }; /* get_ctov thanks to Umberto */ #define _INIT_CTOV_WORD_1 0x00dfbe77 #define _INIT_CTOV_WORD_2 0x023126e9 uint8_t get_ctov( uint32_t r0, uint32_t r1 ) { r0 = r0 * _INIT_CTOV_WORD_1; r0 += ( r1 << 22 ); r0 += _INIT_CTOV_WORD_2; r0 = (uint32_t)(((int32_t)r0) >> 25); return (uint8_t)r0; } /* radio_init has been tested to be good */ void radio_init(void) { volatile uint32_t i; /* sequence 1 */ for(i=0; i>18) | PAVAL[power]; */ #ifdef USE_PA reg(ADDR_POW2) = 0xffffdfff & PAVAL[power]; /* single port */ #else reg(ADDR_POW2) = 0x00002000 | PAVAL[power]; /* dual port */ #endif reg(ADDR_POW3) = AIMVAL[power]; irq_restore(); if(bit_is_set(*NIPEND, INT_NUM_MACA)) { *INTFRC = (1 << INT_NUM_MACA); } } const uint8_t VCODivI[16] = { 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, }; const uint32_t VCODivF[16] = { 0x00355555, 0x006aaaaa, 0x00a00000, 0x00d55555, 0x010aaaaa, 0x01400000, 0x01755555, 0x01aaaaaa, 0x01e00000, 0x00155555, 0x004aaaaa, 0x00800000, 0x00b55555, 0x00eaaaaa, 0x01200000, 0x01555555, }; /* tested good */ #define ADDR_CHAN1 0x80009800 #define ADDR_CHAN2 (ADDR_CHAN1+12) #define ADDR_CHAN3 (ADDR_CHAN1+16) #define ADDR_CHAN4 (ADDR_CHAN1+48) void set_channel(uint8_t chan) { volatile uint32_t tmp; safe_irq_disable(MACA); tmp = reg(ADDR_CHAN1); tmp = tmp & 0xbfffffff; reg(ADDR_CHAN1) = tmp; reg(ADDR_CHAN2) = VCODivI[chan]; reg(ADDR_CHAN3) = VCODivF[chan]; tmp = reg(ADDR_CHAN4); tmp = tmp | 2; reg(ADDR_CHAN4) = tmp; tmp = reg(ADDR_CHAN4); tmp = tmp | 4; reg(ADDR_CHAN4) = tmp; tmp = tmp & 0xffffe0ff; tmp = tmp | (((ctov[chan])<<8)&0x1F00); reg(ADDR_CHAN4) = tmp; /* duh! */ irq_restore(); if(bit_is_set(*NIPEND, INT_NUM_MACA)) { *INTFRC = (1 << INT_NUM_MACA); } } uint8_t (*get_lqi)(void) = (void *) 0x0000e04d; #define ROM_END 0x0013ffff #define ENTRY_EOF 0x00000e0f /* processes up to 4 words of initialization entries */ /* returns the number of words processed */ uint32_t exec_init_entry(volatile uint32_t *entries, uint8_t *valbuf) { volatile uint32_t i; if(entries[0] <= ROM_END) { if (entries[0] == 0) { /* do delay command*/ PRINTF("init_entry: delay 0x%08x\n\r", (unsigned int)entries[1]); for(i=0; i= 16) && (entries[0] < 0xfff1)) { /* store bytes in valbuf */ PRINTF("init_entry: store in valbuf 0x%02x position %d\n\r", (unsigned int)entries[1], (unsigned int)(entries[0]>>4)-1); valbuf[(entries[0]>>4)-1] = entries[1]; return 2; } else if (entries[0] == ENTRY_EOF) { PRINTF("init_entry: eof "); return 0; } else { /* invalid command code */ PRINTF("init_entry: invaild code 0x%08x\n\r",(unsigned int)entries[0]); return 0; } } else { /* address isn't in ROM space */ /* do store value in address command */ PRINTF("init_entry: address value pair - *0x%08x = 0x%08x\n\r", (unsigned int)entries[0], (unsigned int)entries[1]); if ((unsigned int)entries[0] != (unsigned int)CRM_VREG_CNTL) { reg(entries[0]) = entries[1]; } else { PRINTF("skipping VREG_CNTL\n\r"); } return 2; } } #define FLASH_INIT_MAGIC 0x00000abc uint32_t init_from_flash(uint32_t addr) { nvmType_t type=0; nvmErr_t err; volatile uint32_t buf[8]; volatile uint32_t len; volatile uint32_t i=0,j; err = nvm_detect(gNvmInternalInterface_c, &type); PRINTF("nvm_detect returned type 0x%08x err 0x%02x\n\r", type, err); nvm_setsvar(0); err = nvm_read(gNvmInternalInterface_c, type, (uint8_t *)buf, addr, 8); i+=8; PRINTF("nvm_read returned: 0x%02x\n\r",err); for(j=0; j<4; j++) { PRINTF("0x%08x\n\r",(unsigned int)buf[j]); } if(buf[0] == FLASH_INIT_MAGIC) { len = buf[1] & 0x0000ffff; while(i < (len-4)) { err = nvm_read(gNvmInternalInterface_c, type, (uint8_t *)buf, addr+i, 32); i += 4*exec_init_entry(buf, ram_values); } } else { i = 0; } nvm_setsvar(1); return i; } /* * Do the ABORT-Wait-NOP-Wait sequence in order to prevent MACA malfunctioning. * This seqeunce is synchronous and no interrupts should be triggered when it is done. */ void ResumeMACASync(void) { volatile uint32_t clk, TsmRxSteps, LastWarmupStep, LastWarmupData, LastWarmdownStep, LastWarmdownData; // bool_t tmpIsrStatus; volatile uint32_t i; safe_irq_disable(MACA); // ITC_DisableInterrupt(gMacaInt_c); // AppInterrupts_ProtectFromMACAIrq(tmpIsrStatus); <- Original from MAC code, but not sure how is it implemented /* Manual TSM modem shutdown */ /* read TSM_RX_STEPS */ TsmRxSteps = (*((volatile uint32_t *)(0x80009204))); /* isolate the RX_WU_STEPS */ /* shift left to align with 32-bit addressing */ LastWarmupStep = (TsmRxSteps & 0x1f) << 2; /* Read "current" TSM step and save this value for later */ LastWarmupData = (*((volatile uint32_t *)(0x80009300 + LastWarmupStep))); /* isolate the RX_WD_STEPS */ /* right-shift bits down to bit 0 position */ /* left-shift to align with 32-bit addressing */ LastWarmdownStep = ((TsmRxSteps & 0x1f00) >> 8) << 2; /* write "last warmdown data" to current TSM step to shutdown rx */ LastWarmdownData = (*((volatile uint32_t *)(0x80009300 + LastWarmdownStep))); (*((volatile uint32_t *)(0x80009300 + LastWarmupStep))) = LastWarmdownData; /* Abort */ MACA_WRITE(maca_control, 1); /* Wait ~8us */ for (clk = maca_clk, i = 0; maca_clk - clk < 3 && i < 300; i++) ; /* NOP */ MACA_WRITE(maca_control, 0); /* Wait ~8us */ for (clk = maca_clk, i = 0; maca_clk - clk < 3 && i < 300; i++) ; /* restore original "last warmup step" data to TSM (VERY IMPORTANT!!!) */ (*((volatile uint32_t *)(0x80009300 + LastWarmupStep))) = LastWarmupData; /* Clear all MACA interrupts - we should have gotten the ABORT IRQ */ MACA_WRITE(maca_clrirq, 0xFFFF); // AppInterrupts_UnprotectFromMACAIrq(tmpIsrStatus); <- Original from MAC code, but not sure how is it implemented // ITC_EnableInterrupt(gMacaInt_c); // enable_irq(MACA); irq_restore(); }