Exemplo n.º 1
0
/***************************************************************************//**
 * @brief dds_set_phase
*******************************************************************************/
void dds_set_scale(uint32_t chan, double scale)
{
	uint32_t scale_reg;
	uint32_t sign_part;
	uint32_t int_part;
	uint32_t fract_part;

	if (PCORE_VERSION_MAJOR(dds_st.pcore_version) > 6)
	{
		if(scale >= 1.0)
		{
			sign_part = 0;
			int_part = 1;
			fract_part = 0;
			dds_st.cached_scale[chan] = 1.0;
			goto set_scale_reg;
		}
		if(scale <= -1.0)
		{
			sign_part = 1;
			int_part = 1;
			fract_part = 0;
			dds_st.cached_scale[chan] = -1.0;
			goto set_scale_reg;
		}
		if(scale < 0)
		{
			sign_part = 1;
			int_part = 0;
			dds_st.cached_scale[chan] = scale;
			scale *= -1;
			goto set_scale_reg;
		}
		sign_part = 0;
		int_part = 0;
		dds_st.cached_scale[chan] = scale;
		fract_part = (uint32_t)(scale * 0x4000);
	set_scale_reg:
		scale_reg = (sign_part << 15) | (int_part << 14) | fract_part;
	}
	else
	{
		if(scale >= 1.0)
		{
			scale_reg = 0;
			scale = 1.0;
		}
		if(scale <= 0.0)
		{
			scale_reg = 0;
			scale = 0.0;
		}
		dds_st.cached_scale[chan] = scale;
		fract_part = (uint32_t)(scale * 1000000);
		scale_reg = 500000 / fract_part;
	}
	dac_stop();
	dac_write(ADI_REG_CHAN_CNTRL_1_IIOCHAN(chan), ADI_DDS_SCALE(scale_reg));
	dac_start_sync(0);
}
Exemplo n.º 2
0
/***************************************************************************//**
 * @brief dds_set_frequency
*******************************************************************************/
void dds_set_frequency(uint32_t chan, uint32_t freq)
{
	uint64_t val64;
	uint32_t reg;

	dds_st.cached_freq[chan] = freq;
	dac_stop();
	dac_read(ADI_REG_CHAN_CNTRL_2_IIOCHAN(chan), &reg);
	reg &= ~ADI_DDS_INCR(~0);
	val64 = (uint64_t) freq * 0xFFFFULL;
	do_div(&val64, *dds_st.dac_clk);
	reg |= ADI_DDS_INCR(val64) | 1;
	dac_write(ADI_REG_CHAN_CNTRL_2_IIOCHAN(chan), reg);
	dac_start_sync(0);
}
Exemplo n.º 3
0
/***************************************************************************//**
 * @brief dds_set_phase
*******************************************************************************/
void dds_set_phase(uint32_t chan, uint32_t phase)
{
	uint64_t val64;
	uint32_t reg;

	dds_st.cached_phase[chan] = phase;
	dac_stop();
	dac_read(ADI_REG_CHAN_CNTRL_2_IIOCHAN(chan), &reg);
	reg &= ~ADI_DDS_INIT(~0);
	val64 = (uint64_t) phase * 0x10000ULL + (360000 / 2);
	do_div(&val64, 360000);
	reg |= ADI_DDS_INIT(val64);
	dac_write(ADI_REG_CHAN_CNTRL_2_IIOCHAN(chan), reg);
	dac_start_sync(0);
}
Exemplo n.º 4
0
/***************************************************************************//**
 * @brief dds_set_frequency
*******************************************************************************/
void dds_set_frequency(struct ad9361_rf_phy *phy, uint32_t chan, uint32_t freq)
{
	uint64_t val64;
	uint32_t reg;

	dds_st[phy->id_no].cached_freq[chan] = freq;
	dac_stop(phy);
	dac_read(phy, DAC_REG_CHAN_CNTRL_2_IIOCHAN(chan), &reg);
	reg &= ~DAC_DDS_INCR(~0);
	val64 = (uint64_t) freq * 0xFFFFULL;
	do_div(&val64, *dds_st[phy->id_no].dac_clk);
	reg |= DAC_DDS_INCR(val64) | 1;
	dac_write(phy, DAC_REG_CHAN_CNTRL_2_IIOCHAN(chan), reg);
	dac_start_sync(phy, 0);
}
Exemplo n.º 5
0
/***************************************************************************//**
 * @brief dds_set_phase
*******************************************************************************/
void dds_set_phase(struct ad9361_rf_phy *phy, uint32_t chan, uint32_t phase)
{
	uint64_t val64;
	uint32_t reg;

	dds_st[phy->id_no].cached_phase[chan] = phase;
	dac_stop(phy);
	dac_read(phy, DAC_REG_CHAN_CNTRL_2_IIOCHAN(chan), &reg);
	reg &= ~DAC_DDS_INIT(~0);
	val64 = (uint64_t) phase * 0x10000ULL + (360000 / 2);
	do_div(&val64, 360000);
	reg |= DAC_DDS_INIT(val64);
	dac_write(phy, DAC_REG_CHAN_CNTRL_2_IIOCHAN(chan), reg);
	dac_start_sync(phy, 0);
}
Exemplo n.º 6
0
/* playback_set_src
 *
 * Change the playback source. This will be refused if the current source
 * is an active network stream.
 */
int playback_set_src(enum playback_source new_src) {
	/* Can't switch away from network while playing. */
	if (playback_src == SRC_NETWORK && new_src != SRC_NETWORK
	    && dac_get_state() != DAC_IDLE) {
		return -1;
	}

	if (playback_src == new_src)
		return 0;

	/* Stop the DAC and set playback_src_flags to 0, which will prevent
	 * the abstract generator and ILDA player from producing output. */
	dac_stop(DAC_FLAG_STOP_SRCSWITCH);
	playback_source_flags = 0;
	playback_src = new_src;

	return 0;
}
Exemplo n.º 7
0
/***************************************************************************//**
 * @brief dac_init
*******************************************************************************/
void dac_init(struct ad9361_rf_phy *phy, uint8_t data_sel)
{
	uint32_t tx_count;
	uint32_t index;
	uint32_t index_i1;
	uint32_t index_q1;
	uint32_t index_i2;
	uint32_t index_q2;
	uint32_t data_i1;
	uint32_t data_q1;
	uint32_t data_i2;
	uint32_t data_q2;

	dac_write(ADI_REG_RSTN, 0x0);
	dac_write(ADI_REG_RSTN, ADI_RSTN | ADI_MMCM_RSTN);

	dac_write(ADI_REG_RATECNTRL, ADI_RATE(3));

	dds_st.dac_clk = &phy->clks[TX_SAMPL_CLK]->rate;
	dds_st.num_dds_channels = 8;	// FIXME

	dac_read(ADI_REG_VERSION, &dds_st.pcore_version);

	dac_stop();
	switch (data_sel) {
	case DATA_SEL_DDS:
		dds_default_setup(DDS_CHAN_TX1_I_F1, 90000, 1000000, 0.25);
		dds_default_setup(DDS_CHAN_TX1_I_F2, 90000, 1000000, 0.25);
		dds_default_setup(DDS_CHAN_TX1_Q_F1, 0, 1000000, 0.25);
		dds_default_setup(DDS_CHAN_TX1_Q_F2, 0, 1000000, 0.25);
		dds_default_setup(DDS_CHAN_TX2_I_F1, 90000, 1000000, 0.25);
		dds_default_setup(DDS_CHAN_TX2_I_F2, 90000, 1000000, 0.25);
		dds_default_setup(DDS_CHAN_TX2_Q_F1, 0, 1000000, 0.25);
		dds_default_setup(DDS_CHAN_TX2_Q_F2, 0, 1000000, 0.25);
		dac_write(ADI_REG_CNTRL_2, 0);
		dac_datasel(-1, DATA_SEL_DDS);
		break;
	case DATA_SEL_DMA:
		tx_count = sizeof(sine_lut) / sizeof(uint16_t);
		for(index = 0; index < (tx_count * 2); index += 2)
		{
			index_i1 = index;
			index_q1 = index + (tx_count / 2);
			if(index_q1 >= (tx_count * 2))
				index_q1 -= (tx_count * 2);
			data_i1 = (sine_lut[index_i1 / 2] << 20);
			data_q1 = (sine_lut[index_q1 / 2] << 4);
			// FIXME

			index_i2 = index_i1;
			index_q2 = index_q1;
			if(index_i2 >= (tx_count * 2))
				index_i2 -= (tx_count * 2);
			if(index_q2 >= (tx_count * 2))
				index_q2 -= (tx_count * 2);
			data_i2 = (sine_lut[index_i2 / 2] << 20);
			data_q2 = (sine_lut[index_q2 / 2] << 4);
			// FIXME
		}
		dac_dma_write(AXI_DMAC_REG_CTRL, 0);
		dac_dma_write(AXI_DMAC_REG_CTRL, AXI_DMAC_CTRL_ENABLE);
		// FIXME dac_dma_write(AXI_DMAC_REG_SRC_ADDRESS, DAC_DDR_BASEADDR);
		dac_dma_write(AXI_DMAC_REG_SRC_STRIDE, 0x0);
		dac_dma_write(AXI_DMAC_REG_X_LENGTH, (tx_count * 8) - 1);
		dac_dma_write(AXI_DMAC_REG_Y_LENGTH, 0x0);
		dac_dma_write(AXI_DMAC_REG_START_TRANSFER, 0x1);
		dac_write(ADI_REG_CNTRL_2, 0);
		dac_datasel(-1, DATA_SEL_DMA);
		break;
	default:
		break;
	}
	dds_st.enable = true;
	dac_start_sync(0);
}
Exemplo n.º 8
0
/***************************************************************************//**
 * @brief dds_set_phase
*******************************************************************************/
void dds_set_scale(struct ad9361_rf_phy *phy, uint32_t chan, int32_t scale_micro_units)
{
	uint32_t scale_reg;
	uint32_t sign_part;
	uint32_t int_part;
	uint32_t fract_part;

	if (PCORE_VERSION_MAJOR(dds_st[phy->id_no].pcore_version) > 6)
	{
		if(scale_micro_units >= 1000000)
		{
			sign_part = 0;
			int_part = 1;
			fract_part = 0;
			dds_st[phy->id_no].cached_scale[chan] = 1000000;
			goto set_scale_reg;
		}
		if(scale_micro_units <= -1000000)
		{
			sign_part = 1;
			int_part = 1;
			fract_part = 0;
			dds_st[phy->id_no].cached_scale[chan] = -1000000;
			goto set_scale_reg;
		}
		dds_st[phy->id_no].cached_scale[chan] = scale_micro_units;
		if(scale_micro_units < 0)
		{
			sign_part = 1;
			int_part = 0;
			scale_micro_units *= -1;
		}
		else
		{
			sign_part = 0;
			int_part = 0;
		}
		fract_part = (uint32_t)(((uint64_t)scale_micro_units * 0x4000) / 1000000);
	set_scale_reg:
		scale_reg = (sign_part << 15) | (int_part << 14) | fract_part;
	}
	else
	{
		if(scale_micro_units >= 1000000)
		{
			scale_reg = 0;
			scale_micro_units = 1000000;
		}
		if(scale_micro_units <= 0)
		{
			scale_reg = 0;
			scale_micro_units = 0;
		}
		dds_st[phy->id_no].cached_scale[chan] = scale_micro_units;
		fract_part = (uint32_t)(scale_micro_units);
		scale_reg = 500000 / fract_part;
	}
	dac_stop(phy);
	dac_write(phy, DAC_REG_CHAN_CNTRL_1_IIOCHAN(chan), DAC_DDS_SCALE(scale_reg));
	dac_start_sync(phy, 0);
}
Exemplo n.º 9
0
/* recv_fsm
 *
 * Attempt to process some data from the buffer located at 'data'.
 *
 * If a command is succcessfully read, then this returns the number of bytes
 * consumed from the buffer. If a partial command is present in the buffer,
 * but not enough to process yet, then this will return 0; the invoking
 * function should call it later when more data is available. If an error
 * occurs such that no further data can be handled from the connection, then
 * this will call close_conn on the connection and return -1.
 */
static int recv_fsm(struct tcp_pcb *pcb, uint8_t * data, int len) {
	uint8_t cmd = *data;
	int npoints;

	switch (ps_state) {
	case MAIN:
		switch (cmd) {
		case 'p':
			/* Prepare stream. */
			if (dac_prepare() < 0) {
				return send_resp(pcb, RESP_NAK_INVL, cmd, 1);
			} else {
				return send_resp(pcb, RESP_ACK, cmd, 1);
			}

		case 'b':
			/* Make sure we have all of this packet... */
			if (len < sizeof(struct begin_command))
				return 0;

			struct begin_command *bc = (struct begin_command *)data;

			if (bc->point_rate > DAC_MAX_POINT_RATE)
				return send_resp(pcb, RESP_NAK_INVL, cmd, 1);

// XXX			set_low_water_mark(bc->low_water_mark);
			dac_set_rate(bc->point_rate);
			dac_start();

			return send_resp(pcb, RESP_ACK, cmd,
					 sizeof(struct begin_command));

		case 'u':
			/* Update and Begin use the same packet format */
			if (len < sizeof(struct begin_command))
				return 0;

			struct begin_command *uc = (struct begin_command *)data;

			if (uc->point_rate > DAC_MAX_POINT_RATE)
				return send_resp(pcb, RESP_NAK_INVL, cmd, 1);

			dac_set_rate(uc->point_rate);
// XXX			set_low_water_mark(uc->low_water_mark);

			return send_resp(pcb, RESP_ACK, cmd, 
					 sizeof(struct begin_command));

		case 'q':
			if (len < sizeof(struct queue_command))
				return 0;

			struct queue_command *qc = (struct queue_command *)data;

			if (qc->point_rate > DAC_MAX_POINT_RATE)
				return send_resp(pcb, RESP_NAK_INVL, cmd, 1);

			dac_rate_queue(qc->point_rate);

			return send_resp(pcb, RESP_ACK, cmd, 
					 sizeof(struct queue_command));

		case 'd':
			/* Data: switch into the DATA state to start reading
			 * points into the buffer. */
			if (len < sizeof(struct data_command))
				return 0;

			struct data_command *h = (struct data_command *) data;

			if (h->npoints) {
				ps_state = DATA;
				ps_pointsleft = h->npoints;

				/* We'll send a response once we've read all
				 * of the data. */
				return sizeof(struct data_command);
			} else {
				/* 0-length data packets are legit. */
				return send_resp(pcb, RESP_ACK, cmd,
					sizeof(struct data_command));
			}

		case 's':
			/* Stop */
			if (dac_get_state() == DAC_IDLE) {
				return send_resp(pcb, RESP_NAK_INVL, cmd, 1);
			} else {
				dac_stop(0);
				return send_resp(pcb, RESP_ACK, cmd, 1);
			}

		case 0:
		case 0xFF:
			/* Emergency-stop. */
			le_estop(ESTOP_PACKET);
			return send_resp(pcb, RESP_ACK, cmd, 1);

		case 'c':
			/* Clear e-stop. */
			le_estop_clear(ESTOP_CLEAR_ALL);
			if (le_get_state() == LIGHTENGINE_READY)
				return send_resp(pcb, RESP_ACK, cmd, 1);
			else
				return send_resp(pcb, RESP_NAK_ESTOP, cmd, 1);

		case '?':
			/* Ping */
			return send_resp(pcb, RESP_ACK, cmd, 1);

		default:
			outputf("unknown cmd 0x%02x", cmd);
			return close_conn(pcb, CONNCLOSED_UNKNOWNCMD, -1);
		}

		return -1;

	case DATA:
		ASSERT_NOT_EQUAL(ps_pointsleft, 0);

		/* We can only write a complete point at a time. */
		if (len < sizeof(struct dac_point))
			return 0;

		/* How many bytes of data is it our business to write? */
		npoints = len / sizeof(struct dac_point);
		if (npoints > ps_pointsleft)
			npoints = ps_pointsleft;

		/* How much do we have room for now? Note that dac_prepare
		 * is a ring buffer, so it's OK if it returns less than the
		 * number of points we have ready for it. We'll just have
		 * the FSM invoke us again. */
		int nready = dac_request();
		packed_point_t *addr = dac_request_addr();

		/* On the other hand, if the DAC isn't ready for *any* data,
		 * then ignore the rest of this write command and NAK when
		 * it's over. The FSM will take care of us... */
		if (nready <= 0) {
			if (nready == 0) {
				outputf("overflow: wanted to write %d", npoints);
			} else {
				outputf("underflow: pl %d np %d r %d", ps_pointsleft, npoints, nready);
			}
			ps_state = DATA_ABORTING;

			/* Danger: goto. This could probably be structured
			 * better... */
			goto handle_aborted_data;
		}

		if (npoints > nready)
			npoints = nready;

		dac_point_t *pdata = (dac_point_t *)data;

		int i;
		for (i = 0; i < npoints; i++) {
			dac_pack_point(addr + i, pdata + i);
		}

		/* Let the DAC know we've given it more data */
		dac_advance(npoints);

		ps_pointsleft -= npoints;

		if (!ps_pointsleft) {
			ps_state = MAIN;
			return send_resp(pcb, RESP_ACK, 'd',
					 npoints * sizeof(struct dac_point));
		} else {
			return (npoints * sizeof(struct dac_point));
		}

	case DATA_ABORTING:
		ASSERT_NOT_EQUAL(ps_pointsleft, 0);

		/* We can only consume a complete point at a time. */
		if (len < sizeof(struct dac_point))
			return 0;

		/* How many points do we have? */
		npoints = len / sizeof(struct dac_point);
		if (npoints > ps_pointsleft)
			npoints = ps_pointsleft;

handle_aborted_data:
		ps_pointsleft -= npoints;

		if (!ps_pointsleft) {
			ps_state = MAIN;
			return send_resp(pcb, RESP_NAK_INVL, 'd',
					 npoints * sizeof(struct dac_point));
		} else {
			return (npoints * sizeof(struct dac_point));
		}

	default:
		break;
	}

	panic("invalid state in recv_dfa");
	return -1;
}
Exemplo n.º 10
0
static void ilda_stop_FPV_param(const char *path) {
	playback_source_flags &= ~ILDA_PLAYER_PLAYING;
	dac_stop(0);
}
Exemplo n.º 11
0
/***************************************************************************//**
 * @brief dac_init
*******************************************************************************/
void dac_init(struct ad9361_rf_phy *phy, uint8_t data_sel, uint8_t config_dma)
{
	uint32_t tx_count;
	uint32_t index;
	uint32_t index_i1;
	uint32_t index_q1;
	uint32_t index_i2;
	uint32_t index_q2;
	uint32_t index_mem;
	uint32_t data_i1;
	uint32_t data_q1;
	uint32_t data_i2;
	uint32_t data_q2;
	uint32_t length;

	dac_write(phy, DAC_REG_RSTN, 0x0);
	dac_write(phy, DAC_REG_RSTN, DAC_RSTN | DAC_MMCM_RSTN);

	dds_st[phy->id_no].dac_clk = &phy->clks[TX_SAMPL_CLK]->rate;
	dds_st[phy->id_no].rx2tx2 = phy->pdata->rx2tx2;
	if(dds_st[phy->id_no].rx2tx2)
	{
		dds_st[phy->id_no].num_buf_channels = 4;
		dac_write(phy, DAC_REG_RATECNTRL, DAC_RATE(3));
	}
	else
	{
		dds_st[phy->id_no].num_buf_channels = 2;
		dac_write(phy, DAC_REG_RATECNTRL, DAC_RATE(1));
	}

	dac_read(phy, DAC_REG_VERSION, &dds_st[phy->id_no].pcore_version);

	dac_stop(phy);
	switch (data_sel) {
	case DATA_SEL_DDS:
		dds_default_setup(phy, DDS_CHAN_TX1_I_F1, 90000, 1000000, 250000);
		dds_default_setup(phy, DDS_CHAN_TX1_I_F2, 90000, 1000000, 250000);
		dds_default_setup(phy, DDS_CHAN_TX1_Q_F1, 0, 1000000, 250000);
		dds_default_setup(phy, DDS_CHAN_TX1_Q_F2, 0, 1000000, 250000);
		if(dds_st[phy->id_no].rx2tx2)
		{
			dds_default_setup(phy, DDS_CHAN_TX2_I_F1, 90000, 1000000, 250000);
			dds_default_setup(phy, DDS_CHAN_TX2_I_F2, 90000, 1000000, 250000);
			dds_default_setup(phy, DDS_CHAN_TX2_Q_F1, 0, 1000000, 250000);
			dds_default_setup(phy, DDS_CHAN_TX2_Q_F2, 0, 1000000, 250000);
		}
		dac_write(phy, DAC_REG_CNTRL_2, 0);
		dac_datasel(phy, -1, DATA_SEL_DDS);
		break;
	case DATA_SEL_DMA:
		if(config_dma)
		{
			tx_count = sizeof(sine_lut) / sizeof(uint16_t);
			if(dds_st[phy->id_no].rx2tx2)
			{
#ifdef FMCOMMS5
				for(index = 0, index_mem = 0; index < (tx_count * 2); index += 2, index_mem += 4)
#else
				for(index = 0, index_mem = 0; index < (tx_count * 2); index += 2, index_mem += 2)
#endif
				{
					index_i1 = index;
					index_q1 = index + (tx_count / 2);
					if(index_q1 >= (tx_count * 2))
						index_q1 -= (tx_count * 2);
					data_i1 = (sine_lut[index_i1 / 2] << 20);
					data_q1 = (sine_lut[index_q1 / 2] << 4);
					Xil_Out32(DAC_DDR_BASEADDR + index_mem * 4, data_i1 | data_q1);

					index_i2 = index_i1;
					index_q2 = index_q1;
					if(index_i2 >= (tx_count * 2))
						index_i2 -= (tx_count * 2);
					if(index_q2 >= (tx_count * 2))
						index_q2 -= (tx_count * 2);
					data_i2 = (sine_lut[index_i2 / 2] << 20);
					data_q2 = (sine_lut[index_q2 / 2] << 4);
					Xil_Out32(DAC_DDR_BASEADDR + (index_mem + 1) * 4, data_i2 | data_q2);
#ifdef FMCOMMS5
					Xil_Out32(DAC_DDR_BASEADDR + (index_mem + 2) * 4, data_i1 | data_q1);
					Xil_Out32(DAC_DDR_BASEADDR + (index_mem + 3) * 4, data_i2 | data_q2);
#endif
				}
			}
			else
			{
				for(index = 0; index < tx_count; index += 1)
				{
					index_i1 = index;
					index_q1 = index + (tx_count / 4);
					if(index_q1 >= tx_count)
						index_q1 -= tx_count;
					data_i1 = (sine_lut[index_i1] << 20);
					data_q1 = (sine_lut[index_q1] << 4);
					Xil_Out32(DAC_DDR_BASEADDR + index * 4, data_i1 | data_q1);
				}
			}
			Xil_DCacheFlush();
			if(dds_st[phy->id_no].rx2tx2)
			{
				length = (tx_count * 8);
			}
			else
			{
				length = (tx_count * 4);
			}
#ifdef FMCOMMS5
			length = (tx_count * 16);
#endif
			dac_dma_write(AXI_DMAC_REG_CTRL, 0);
			dac_dma_write(AXI_DMAC_REG_CTRL, AXI_DMAC_CTRL_ENABLE);
			dac_dma_write(AXI_DMAC_REG_SRC_ADDRESS, DAC_DDR_BASEADDR);
			dac_dma_write(AXI_DMAC_REG_SRC_STRIDE, 0x0);
			dac_dma_write(AXI_DMAC_REG_X_LENGTH, length - 1);
			dac_dma_write(AXI_DMAC_REG_Y_LENGTH, 0x0);
			dac_dma_write(AXI_DMAC_REG_START_TRANSFER, 0x1);
		}
		dac_write(phy, DAC_REG_CNTRL_2, 0);
		dac_datasel(phy, -1, DATA_SEL_DMA);
		break;
	default:
		break;
	}
	dds_st[phy->id_no].enable = true;
	dac_start_sync(phy, 0);
}
Exemplo n.º 12
0
int main(int argc, char **argv) {
	__disable_irq();

	LPC_GPIO2->FIODIR &= ~(1 << 8);
	LPC_SC->PCLKSEL0 = PCLKSEL0_INIT_VALUE;
	LPC_SC->PCLKSEL1 = PCLKSEL1_INIT_VALUE;
	LPC_SC->PCONP = PCONP_INIT_VALUE;
	clock_init();
	serial_init();

	/* Enable bus, usage, and mem faults. */
	SCB->SHCSR |= SCB_SHCSR_MEMFAULTENA_Msk | SCB_SHCSR_BUSFAULTENA_Msk
		| SCB_SHCSR_USGFAULTENA_Msk;

#if 0
	/* Disable write buffers. This is useful for debugging - wild writes
	 * are imprecise exceptions unless the Cortex's write buffering is
	 * disabled. However, this has a significant performance hit, so it
	 * should only be set if necessary. */
	*((uint32_t *)0xE000E008) |= (1<<1);
#endif

	debugf("\r\n###############\r\n");
	debugf("# Ether Dream #\r\n");
	debugf("###############\r\n");
	debugf("Firmware: %s\r\n", build);

	debugf("RSID: %d\r\n", LPC_SC->RSID);
	LPC_SC->RSID = 0xF;

	hw_get_board_rev();
	debugf("Hardware Revision %d\n", hw_board_rev);

	debugf("Starting up: led");
	led_init();
	led_set_frontled(1);

	debugf(" skub");
	skub_init();

	debugf(" lwip\r\n");
	lwip_init();

	clock.time = 0;
	clock.mtime = 0;
	SysTick_Config(SystemCoreClock / 10000);

	/* Initialize hardware */
	FPA_init();

	outputf("Entering main loop...");
	watchdog_init();

	/* Startup might have taken some time, so reset the periodic event
	 * timers. */
	int i;
	for (i = 0; i < (sizeof(events) / sizeof(events[0])); i++) {
		events_last[i] = events[i].start + clock.time;
	}

	__enable_irq();

	playback_set_src(SRC_NETWORK);

	/* Default values */
	dac_set_rate(30000);
	ilda_set_fps_limit(30);

	while (1) {
		watchdog_feed();

		/* Check the stuff we check on each loop iteration. */
		for (i = 0; i < TABLE_LENGTH(poll); i++) {
			poll_table[i].f();
		}

		/* Check for periodic events */
		check_periodic_timers();

		if (f0ad_flag) {
			/* Re-enter the bootloader. */
			outputf("Reentering bootloader...");
			dac_stop(0);
			FORCE_BOOTLOAD_FLAG = FORCE_BOOTLOAD_VALUE;
			__disable_irq();

			/* The watchdog timer will kick us soon... */
			while(1);
		}
	}
}