/* * Release Deep Power Down. We do NOT read the Electronic Signature */ void m25p16_res() { select(); bit_bang_write(M25P16_I_RES); deselect(); /* a few usec between RES and standby */ while(M25P16_WIP()); }
/** * Release Deep Power Down. Read and return the Electronic Signature * must return 0x14 * * \return The old style Electronic Signature. This must be 0x14 */ uint8_t m25p16_res_res() { uint8_t rv; select(); bit_bang_write(M25P16_I_RES); bit_bang_write(M25P16_DUMMY_BYTE); bit_bang_write(M25P16_DUMMY_BYTE); bit_bang_write(M25P16_DUMMY_BYTE); rv = bit_bang_read(); deselect(); /* a few usec between RES and standby */ while(M25P16_WIP()); return rv; }
/*---------------------------------------------------------------------------*/ static void timer_handler(void *p) { uint8_t *s = p; uint8_t wip; PRINTF("Disco: @ %lu, s: %u\n", clock_seconds(), *s); if(*s == DISCO_STATE_PREPARING) { n740_analog_deactivate(); wip = M25P16_WIP(); n740_analog_activate(); if(wip) { restart_timer(DISCO_TIMEOUT_PREPARE); } else { PRINTF("Disco: Erased %u\n", sector); if((sector & 1) == 0) { sector++; PRINTF("Disco: Next %u\n", sector); n740_analog_deactivate(); m25p16_se(sector); n740_analog_activate(); restart_timer(DISCO_TIMEOUT_PREPARE); } else { PRINTF("Disco: Ready\n"); *s = DISCO_STATE_READY; resp.status = DISCO_CMD_INIT; restart_timer(DISCO_TIMEOUT_ABORT); server_conn->rport = seed.port; uip_ipaddr_copy(&server_conn->ripaddr, &seed.addr); uip_udp_packet_send(server_conn, &resp, DISCO_RESP_LEN_INIT); /* Restore server connection to allow data from any node */ uip_create_unspecified(&server_conn->ripaddr); server_conn->rport = 0; } } } else if(*s == DISCO_STATE_READY) { abort(); } else if(*s == DISCO_STATE_REBOOTING) { watchdog_reboot(); } }
/*---------------------------------------------------------------------------*/ PROCESS_THREAD(serial_flash_process, ev, data) { static struct etimer et; uint8_t i; PROCESS_BEGIN(); PRINTF("Start\n"); memset(r_addr, 0, 3); r_addr[0] = USE_SECTOR; counter = 1; while(1) { /* Delay */ etimer_set(&et, CLOCK_SECOND * 2); PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&et)); leds_on(LEDS_GREEN); if(counter == 0) { n740_analog_deactivate(); rv = m25p16_rdsr(); n740_analog_activate(); /* If counter==0, we started Bulk Erasing earlier. Check if we still are */ if(rv & M25P16_SR_WIP) { PRINTF("Yield [%02x]\n", rv); } else { counter = 1; } } if(counter) { /* * Take us out of Deep Power Down - On first power-on, the device will * go to stand by mode (which is not DP). However, we drop to DP at the * end of every loop. RES must be 0x14. This is the old style signature * and is only still there for backward compatibility. */ n740_analog_deactivate(); rv = m25p16_res_res(); n740_analog_activate(); PRINTF(" RES: 0x%02x\n", rv); n740_analog_deactivate(); rv = M25P16_WIP(); n740_analog_activate(); PRINTF("========\n"); memset(d_buf, 0, MAX_READ_CHUNK); /* * Read Device ID: Return values must be: * man_id: 0x20 (Numonyx) * mem_type: 0x20 * mem_size: 0x15 (2 ^ 0x15 bytes = 2MB) * uid_len: number of bytes in UID * uid: Either all zeroes or a customized factory data content * */ rdid(); /* Check the value of our Status Register (SR) */ rdsr(); /* Enable Write: Set Bit 1 in the SR to 1 (bit WEL) */ PRINTF("WREN\n"); n740_analog_deactivate(); m25p16_wren(); n740_analog_activate(); /* Confirm: SR & 0x02 must be 1 */ rdsr(); /* Disable the WEL bit */ PRINTF("WRDI\n"); n740_analog_deactivate(); m25p16_wrdi(); n740_analog_activate(); /* Confirm: SR & 0x02 must be 0 */ rdsr(); /* Write something to the SR. We don't need to explicitly set WEL, wrsr() * will do it for us. When the cycle ends, WEL will go low */ PRINTF("WRSR\n"); n740_analog_deactivate(); /* For instance, let's protect sector 31 (that's the highest one) */ m25p16_wrsr(M25P16_SR_BP0); /* * While this is running, WEL should remain high and WIP (bit 0) should * also be high. When this ends, WIP and WEL will go low. * * While the write is in ongoing, we can still read the SR to check the * cycle's progress */ while(M25P16_WIP()); n740_analog_activate(); /* Confirm: SR & 0x02 must be 0 */ rdsr(); /* Read MAX_READ_CHUNK bytes from Page 0x000000 */ memset(d_buf, 0, MAX_READ_CHUNK); n740_analog_deactivate(); m25p16_read(r_addr, d_buf, MAX_READ_CHUNK); n740_analog_activate(); PRINTF("READ:"); for(i = 0; i < MAX_READ_CHUNK; i++) { PRINTF(" %02x", d_buf[i]); } PRINTF("\n"); /* Write MAX_READ_CHUNK bytes to the same Page */ PRINTF("WRITE\n"); for(i = 0; i < MAX_READ_CHUNK; i++) { d_buf[i] = i; } n740_analog_deactivate(); /* We don't need to wren() explicitly, pp() will do that for us */ m25p16_pp(r_addr, d_buf, MAX_READ_CHUNK); /* Wait for the cycle */ while(M25P16_WIP()); /* Trash our data buffer */ memset(d_buf, 0, MAX_READ_CHUNK); PRINTF("ERASE\n"); n740_analog_deactivate(); /* Bulk erase every 4 loops, sector erase otherwise */ /* Bulk Erase: This takes a few seconds so we can't really block on it. * It'd be a bad thing to do and the watchdog would bark anyway. * Bulk Erase will only be accepted if all SR_BP[2:0] == 0 */ if((counter % 4) == 0) { m25p16_wrsr(0); while(M25P16_WIP()); m25p16_be(); counter = 0; } else { m25p16_se(USE_SECTOR); while(M25P16_WIP()); /* Drop to Deep Power Down */ m25p16_dp(); counter ++; } n740_analog_activate(); } leds_off(LEDS_GREEN); } PROCESS_END(); }
/*---------------------------------------------------------------------------*/ void batmon_log(uint8_t trigger) { uint32_t next; /* Only continue if the process (us) is running */ if(!process_is_running(&batmon_process)) { return; } next = f.a; next |= (((uint32_t) f.p) << 8); next |= (((uint32_t) f.s) << 16); memcpy(r.magic, magic, sizeof(magic)); r.trigger = trigger; r.c = clock_seconds(); /* Read VDD and use as ADC reference */ r.v = s->value(ADC_SENSOR_TYPE_VDD); /* And then carry on with battery */ r.b = s->value(ADC_SENSOR_TYPE_BATTERY); #if ENERGEST_CONF_ON /* ENERGEST values */ r.mcu = energest_type_time(ENERGEST_TYPE_CPU); r.lpm = energest_type_time(ENERGEST_TYPE_LPM); r.irq = energest_type_time(ENERGEST_TYPE_IRQ); r.tx = energest_type_time(ENERGEST_TYPE_TRANSMIT); r.rx = energest_type_time(ENERGEST_TYPE_LISTEN); r.f_write = energest_type_time(ENERGEST_TYPE_FLASH_WRITE); r.f_read = energest_type_time(ENERGEST_TYPE_FLASH_READ); #endif n740_analog_deactivate(); /* Make sure we're on */ if(M25P16_WIP()) { m25p16_res(); } m25p16_pp((uint8_t *)&f, (uint8_t *)&r, sizeof(r)); n740_analog_activate(); PRINTF("BatMon: @%lu [%u] ", r.c, r.trigger); PRINTF("BatMon: 0x%02x%02x%02x\n", f.s, f.p, f.a); next += RECORD_SIZE; if(next >= FLASH_END_ADDR) { abort(); return; } f.s = ((next & 0xFF0000) >> 16); f.p = ((next & 0xFF00) >> 8); f.a = next & 0xFF; if(trigger == LOG_TRIGGER_PERIODIC) { etimer_reset(&et); } }