예제 #1
0
int main(void)
{
//! [main_setup]
//! [system_init]
	system_init();
//! [system_init]
//! [run_config]
	configure_spi_master();
//! [run_config]
//! [main_setup]

//! [main_use_case]
//! [inf_loop]
	while (true) {
		/* Infinite loop */
		if(!port_pin_get_input_level(BUTTON_0_PIN)) {
			//! [select_slave]
			spi_select_slave(&spi_master_instance, &slave, true);
			//! [select_slave]
			//! [write]
			spi_write_buffer_wait(&spi_master_instance, buffer, BUF_LENGTH);
			//! [write]
			//! [deselect_slave]
			spi_select_slave(&spi_master_instance, &slave, false);
			//! [deselect_slave]
			//! [light_up]
			port_pin_set_output_level(LED_0_PIN, LED0_ACTIVE);
			//! [light_up]
		}
	}
//! [inf_loop]
//! [main_use_case]
}
/**
 * \brief Write a register value.
 *
 * \param reg the register address to modify.
 * \param wrdata the new register value.
 */
void ksz8851_reg_write(uint16_t reg, uint16_t wrdata)
{
	uint8_t	inbuf[4];
	uint8_t	outbuf[4];
	uint16_t cmd = 0;

	spi_select_slave(&ksz8851snl_master, &ksz8851snl_slave, true);

	/* Move register address to cmd bits 9-2, make 32-bit address. */
	cmd = (reg << 2) & REG_ADDR_MASK;

	/* Last 2 bits still under "don't care bits" handled with byte enable. */
	/* Select byte enable for command. */
	if (reg & 2) {
		/* Odd word address writes bytes 2 and 3 */
		cmd |= (0xc << 10);
	} else {
		/* Even word address write bytes 0 and 1 */
		cmd |= (0x3 << 10);
	}

	/* Add command write code. */
	cmd |= CMD_WRITE;
	outbuf[0] = cmd >> 8;
	outbuf[1] = cmd & 0xff;
	outbuf[2] = wrdata & 0xff;
	outbuf[3] = wrdata >> 8;

	/* Perform SPI transfer. */
	spi_transceive_buffer_wait(&ksz8851snl_master, outbuf, inbuf, 4);

	spi_select_slave(&ksz8851snl_master, &ksz8851snl_slave, false);
}
/*!
* @brief		Receives data from BMM050 on SPI
*
* @param[in]	dev_addr	Device I2C slave address (not used)
*
* @param[in]	reg_addr	Address of destination register
*
* @param[out]	reg_data	Pointer to data buffer to be received
*
* @param[in]	length		Length of the data to be received
*
* @retval		0			BMG160_SUCCESS
* @retval		-1			BMG160_ERROR
*
*/
int8_t bmg_spi_read(uint8_t dev_addr, uint8_t reg_addr, uint8_t *rx_data, uint8_t length)
{
	enum status_code bmg_read_stat = STATUS_NO_CHANGE;
	
	/* This variable is used to avoid infinite loops. */
	uint16_t loop_count;
	
	uint16_t dummy = 0;
	
	reg_addr = reg_addr | 0x80;
	
	spi_select_slave(&spi_master_instance, &bmg160_spi_slave, true);
	
	loop_count = 0;
	do
	{
		bmg_read_stat = spi_write_buffer_wait(&spi_master_instance, &reg_addr, 1);
		loop_count++;
	}while(bmg_read_stat != STATUS_OK && loop_count < 100);
	
	loop_count = 0;
	do
	{
		bmg_read_stat = spi_read_buffer_wait(&spi_master_instance, rx_data, length, dummy);
		loop_count++;
	}while(bmg_read_stat != STATUS_OK && loop_count < 100);
	
	spi_select_slave(&spi_master_instance, &bmg160_spi_slave, false);
	
	if (bmg_read_stat != STATUS_OK)
	{
		return -1;
	}
	return 0;
}
/**
 * \internal
 * \brief Test sending and receiving 9-bit data by polling.
 *
 * This test sends (writes) one 9-bit data to the slave and
 * receives (reads) the data back and compares.
 *
 * Writing and reading are carried out by polling.
 *
 * \param test Current test case.
 */
static void run_transfer_9bit_test(const struct test_case *test)
{
	uint16_t txd_data = 0x155;
	uint16_t rxd_data = 0;

	/* Skip test if initialization failed */
	test_assert_true(test, spi_init_success,
			"Skipping test due to failed initialization");

	/* Send data to slave */
	spi_select_slave(&master, &slave_inst, true);
	while (!spi_is_ready_to_write(&master)) {
	}
	spi_write(&master, txd_data);
	while (!spi_is_write_complete(&master)) {
	}

	/* Dummy read SPI master data register */
	while (!spi_is_ready_to_read(&master)) {
	}
	spi_read(&master, &rxd_data);

	/* Read SPI slave data register */
	while (!spi_is_ready_to_read(&slave)) {
	}
	spi_read(&slave, &rxd_data);
	spi_select_slave(&master, &slave_inst, false);

	/* Output test result */
	test_assert_true(test, rxd_data == txd_data,
			"Failed transmitting/receiving byte. TX='%d', RX='%d'",
			txd_data, rxd_data);
}
예제 #5
0
파일: ssd1306.c 프로젝트: InSoonPark/asf
/**
 * \brief Writes a command to the display controller
 *
 * This functions pull pin D/C# low before writing to the controller. Different
 * data write function is called based on the selected interface.
 *
 * \param command the command to write
 */
void ssd1306_write_command(uint8_t command)
{
	spi_select_slave(&ssd1306_master, &ssd1306_slave, true);
	port_pin_set_output_level(SSD1306_DC_PIN, false);
	spi_write_buffer_wait(&ssd1306_master, &command, 1);
	spi_select_slave(&ssd1306_master, &ssd1306_slave, false);
}
/**
 * \internal
 * \brief Test: Send & receive data using transceive functions.
 *
 * This test sends (writes) an array of data to the slave and
 * receives (reads) the buffer back using transceive functions
 * and compares.
 *
 * \param test Current test case.
 */
static void run_transceive_buffer_test(const struct test_case *test)
{
	enum status_code status = STATUS_ERR_IO;

	/* Skip test if initialization failed */
	test_assert_true(test, spi_init_success,
			"Skipping test due to failed initialization");

	/* Start the test */
	spi_transceive_buffer_job(&slave, slave_tx_buf, slave_rx_buf,
			BUFFER_LENGTH);
	spi_select_slave(&master, &slave_inst, true);
	status = spi_transceive_buffer_wait(&master, tx_buf, rx_buf,
			BUFFER_LENGTH);
	spi_select_slave(&master, &slave_inst, false);

	test_assert_true(test, status == STATUS_OK,
			"Transceive buffer failed");

	/* Compare received data with transmitted data */
	if (status == STATUS_OK) {
		for (uint16_t i = 0; i < BUFFER_LENGTH; i++) {
			test_assert_true(test, tx_buf[i] == slave_rx_buf[i],
					"During TX: Bytes differ at buffer index %d : %d != %d",
					i, tx_buf[i], slave_rx_buf[i]);
			test_assert_true(test, slave_tx_buf[i] == rx_buf[i],
					"During RX: Bytes differ at buffer index %d : %d != %d",
					i, slave_tx_buf[i], rx_buf[i]);
		}
	}
}
int main(void)
{
//! [main_setup]
//! [system_init]
	system_init();
//! [system_init]
//! [run_config]
	configure_spi_master();
//! [run_config]
//! [main_setup]

//! [main_use_case]
//! [select_slave]
	spi_select_slave(&spi_master_instance, &slave, true);
//! [select_slave]
//! [write]
	spi_write_buffer_wait(&spi_master_instance, buffer, BUF_LENGTH);
//! [write]
//! [deselect_slave]
	spi_select_slave(&spi_master_instance, &slave, false);
//! [deselect_slave]

//! [inf_loop]
	while (true) {
		/* Infinite loop */
	}
//! [inf_loop]
//! [main_use_case]
}
예제 #8
0
파일: ssd1306.c 프로젝트: InSoonPark/asf
/**
 * \brief Write data to the display controller
 *
 * This functions sets the pin D/C# before writing to the controller. Different
 * data write function is called based on the selected interface.
 *
 * \param data the data to write
 */
void ssd1306_write_data(uint8_t data)
{
	spi_select_slave(&ssd1306_master, &ssd1306_slave, true);
	port_pin_set_output_level(SSD1306_DC_PIN, true);
	spi_write_buffer_wait(&ssd1306_master, &data, 1);
	spi_select_slave(&ssd1306_master, &ssd1306_slave, false);
}
예제 #9
0
파일: rom.c 프로젝트: h4xxel/trollbook
void rom_erase() {
	rom_write_enable();
	
	while(rom_status() & 0x1);
	spi_select_slave(SPI_SLAVE_ROM);
	spi_send_recv(ROM_COMMAND_ERASE_CHIP);
	spi_select_slave(SPI_SLAVE_NONE);
}
예제 #10
0
void test_spi_select_slave(void) {
	delay_ms(1);
	spi_select_slave(SPI0, SPI_SELECTOR_0);
	TEST_ASSERT_TRUE((SPI0->SPI_MR & SPI_MR_PCS_MASK) >> 16 == 0b0000);
	spi_select_slave(SPI0, SPI_SELECTOR_1);
	TEST_ASSERT_TRUE((SPI0->SPI_MR & SPI_MR_PCS_MASK) >> 16 == 0b0001);
	spi_select_slave(SPI0, SPI_SELECTOR_2);
	TEST_ASSERT_TRUE((SPI0->SPI_MR & SPI_MR_PCS_MASK) >> 16 == 0b0011);
}
예제 #11
0
int main (void)
{
	system_init();
	
	while ( !system_clock_source_is_ready(SYSTEM_CLOCK_SOURCE_DPLL) ) {
	}
	
	// Disable the pin select for the CAN Controller
	fnc_can_controller_disable();
	
	// Perform the SERCOM configuration for this board
	bastian_complete_sercom_setup();
	
	// TCC Configuration
	tcc_configure_function();		// Counter Configuration
	tcc_callback_configuration();	// Timer Callback Configuration
	
	
	
	
	
	// Select Slave
	spi_select_slave(&spi_master, &spi_shield, false);
	
	// Wait the necessary time for the chip to restart
	inProgress = true;
	intProgressTimer = 100;	// wait for 11ms
	while ( inProgress ) { }
	
	// Read the status from the on-board CAN controller
	spi_select_slave(&spi_master, &spi_CAN_controller, true);
	spi_write_buffer_wait(&spi_master, wr_can_buffer_startup, SYSTEM_SLAVE_TX_SINGLE_BYTE);
	spi_select_slave(&spi_master, &spi_CAN_controller, false);
	
	// Wait the necessary time for the chip to restart
	inProgress = true;
	intProgressTimer = 50;	// wait for 11ms
	while ( inProgress ) { }
	
	spi_select_slave(&spi_master, &spi_CAN_controller, true);
	spi_transceive_buffer_job(&spi_master, &wr_can_buffer_startup[1], rd_buffer, SYSTEM_SLAVE_STATUS_TRANSACTION_LENGTH);
	//spi_select_slave(&spi_master, &spi_CAN_controller, false);
	
// 	inProgress = true;
// 	intProgressTimer = 10;	// wait for 2ms
// 	while ( inProgress ) { }
// 	
// 	spi_select_slave(&spi_master, &spi_CAN_controller, true);
// 	spi_transceive_buffer_job(&spi_master, wr_can_buffer, rd_buffer, SYSTEM_SLAVE_STATUS_TRANSACTION_LENGTH);
	// Main Loop
	while (1) {
		
	}
}
예제 #12
0
파일: rom.c 프로젝트: h4xxel/trollbook
uint8_t rom_status() {
	uint8_t status;
	spi_select_slave(SPI_SLAVE_ROM);
	
	spi_send_recv(ROM_COMMAND_READ_STATUS);
	status = spi_send_recv(0xFF);
	
	spi_select_slave(SPI_SLAVE_NONE);
	
	return status;
}
예제 #13
0
파일: rom.c 프로젝트: h4xxel/trollbook
void rom_read(uint32_t address, uint8_t *buffer, uint32_t size) {
	while(rom_status() & 0x1);
	
	spi_select_slave(SPI_SLAVE_ROM);
	spi_send_recv(ROM_COMMAND_READ_DATA);
	spi_send_recv((address >> 16) & 0xFF);
	spi_send_recv((address >> 8) & 0xFF);
	spi_send_recv(address & 0xFF);
	
	while(size--)
		*buffer++ = spi_send_recv(0xFF);
	
	spi_select_slave(SPI_SLAVE_NONE);	
}
예제 #14
0
enum ab1815_status ab1815_write(struct ab1815_t *clock, uint8_t offset, uint8_t *buf, uint8_t length)
{
	uint8_t buffer[length + 1];
	enum ab1815_status ret_code = ab1815_status_ERROR;
	buffer[0] = AB1815_SPI_WRITE(offset);
	memcpy(buffer + 1, buf, length);
	spi_select_slave(clock->spi_bus, clock->slave, true);
	if(spi_write_buffer_wait(clock->spi_bus, buffer, length + 1) == STATUS_OK)
	{
		ret_code = ab1815_status_OK;
	}
	spi_select_slave(clock->spi_bus, clock->slave, false);
	return ret_code;
};
예제 #15
0
static sint8 spi_rw(uint8* pu8Mosi, uint8* pu8Miso, uint16 u16Sz)
{
	uint8 u8Dummy = 0;
	uint8 u8SkipMosi = 0, u8SkipMiso = 0;
	uint16_t txd_data = 0;
	uint16_t rxd_data = 0;

	if (!pu8Mosi) {
		pu8Mosi = &u8Dummy;
		u8SkipMosi = 1;
	}
	else if(!pu8Miso) {
		pu8Miso = &u8Dummy;
		u8SkipMiso = 1;
	}
	else {
		return M2M_ERR_BUS_FAIL;
	}

	spi_select_slave(&master, &slave_inst, true);

	while (u16Sz) {
		txd_data = *pu8Mosi;
		while (!spi_is_ready_to_write(&master))
			;
		while(spi_write(&master, txd_data) != STATUS_OK)
			;

		/* Read SPI master data register. */
		while (!spi_is_ready_to_read(&master))
			;
		while (spi_read(&master, &rxd_data) != STATUS_OK)
			;
		*pu8Miso = rxd_data;

		u16Sz--;
		if (!u8SkipMiso)
			pu8Miso++;
		if (!u8SkipMosi)
			pu8Mosi++;
	}

	while (!spi_is_write_complete(&master))
		;

	spi_select_slave(&master, &slave_inst, false);

	return M2M_SUCCESS;
}
예제 #16
0
enum ab1815_status ab1815_read(struct ab1815_t *clock, uint8_t offset, uint8_t *buf, uint8_t length)
{
	uint8_t address = AB1815_SPI_READ(offset);
	enum ab1815_status ret_code = ab1815_status_ERROR;
	spi_select_slave(clock->spi_bus, clock->slave, true);
	if(spi_write_buffer_wait(clock->spi_bus, &address, 1) == STATUS_OK)
	{
		if(spi_read_buffer_wait(clock->spi_bus, buf, length, SPI_DUMMY) == STATUS_OK)
		{
			ret_code = ab1815_status_OK;
		}
	}
	spi_select_slave(clock->spi_bus, clock->slave, false);
	return ret_code;
};
예제 #17
0
/**
 * \internal
 * \brief Test: Sends data at different baud rates.
 *
 * This test sends (writes) a byte to the slave and receives the data
 * at different baudrate testing up to the maximum allowed level.
 *
 * Transmission and reception are carried out by polling.
 *
 * \param test Current test case.
 */
static void run_baud_test(const struct test_case *test)
{
	uint32_t test_baud = 1000000;
	uint8_t txd_data   = 0x55;
	uint8_t rxd_data   = 0;
	bool max_baud      = true;

	/* Skip test if initialization failed */
	test_assert_true(test, spi_init_success,
			"Skipping test due to failed initialization");

	/* Structure for SPI configuration */
	struct spi_config config;

	/* Configure the SPI master */
	spi_get_config_defaults(&config);
	config.mux_setting     = CONF_SPI_MASTER_SPI_MUX;
	config.pinmux_pad0     = CONF_SPI_MASTER_DATA_IN_PIN_MUX;
	config.pinmux_pad1     = PINMUX_UNUSED;
	config.pinmux_pad2     = CONF_SPI_MASTER_DATA_OUT_PIN_MUX;
	config.pinmux_pad3     = CONF_SPI_MASTER_SCK_PIN_MUX;

	do {
		spi_disable(&master);
		config.mode_specific.master.baudrate = test_baud;
		spi_init(&master, CONF_SPI_MASTER_MODULE, &config);
		spi_enable(&master);

		/* Send data to slave */
		spi_select_slave(&master, &slave_inst, true);
		spi_write_buffer_wait(&master, &txd_data, 1);
		spi_read_buffer_wait(&slave, &rxd_data, 1, 0);
		spi_select_slave(&master, &slave_inst, false);

		if (txd_data != rxd_data) {
			max_baud = false;
			break;
		}

		test_baud += 1000000;
	} while (test_baud <= 24000000);

	/* Output the result */
	test_assert_true(test, max_baud,
			"Test failed at baudrate: %lu", test_baud);
}
예제 #18
0
/*---------------------------------------------------------------------------*/
void
st7565s_arch_spi_select(bool is_data)
{
  spi_select_slave(&esd_spi_master_instance, &st7565s_spi_slave, true);

  configure_miso(true);

  port_pin_set_output_level(DISPLAY_CMD_DATA_PIN, is_data);
}
/**
 * \brief Complete write operation.
 *
 * \param pad amount of dummy data (bytes) to write to keep 32 bits alignment
 * in the internal FIFO.
 */
void ksz8851_fifo_write_end(uint32_t pad)
{
	uint8_t	outbuf[5];

	if (pad > 0) {
		spi_write_buffer_wait(&ksz8851snl_master, outbuf, 4 - pad);
	}
	spi_select_slave(&ksz8851snl_master, &ksz8851snl_slave, false);
}
예제 #20
0
/*---------------------------------------------------------------------------*/
void
st7565s_arch_spi_deselect(void)
{
  port_pin_set_output_level(DISPLAY_CMD_DATA_PIN, false);

  configure_miso(false);

  spi_select_slave(&esd_spi_master_instance, &st7565s_spi_slave, false);
}
예제 #21
0
void test_spi_write() {
	// Copy of test_spi_write_ready()
	spi_enable(SPI0);
	spi_select_slave(SPI0, SPI_SELECTOR_0);
	TEST_ASSERT_TRUE(spi_tx_ready(SPI0));
	spi_write(SPI0, 0b01011010);
	TEST_ASSERT_FALSE(spi_tx_ready(SPI0));
	delay_ms(1);
	TEST_ASSERT_TRUE(spi_tx_ready(SPI0));
}
예제 #22
0
void test_spi_read_ready() {
	delay_ms(1);
	spi_enable(SPI0);
	spi_select_slave(SPI0, SPI_SELECTOR_0);
	spi_read(SPI0);
	spi_write(SPI0, 0b00011100);
	TEST_ASSERT_FALSE(spi_rx_ready(SPI0));
	delay_ms(1);
	TEST_ASSERT_TRUE(spi_rx_ready(SPI0));
}
예제 #23
0
파일: target.c 프로젝트: kamejoko80/emb6
//!  [hal_spiSlaveSel]
uint8_t hal_spiSlaveSel(void * p_spi, bool action)
{
    if (p_spi == NULL) {
//        LOG_ERR("SPI was not initialized!");
        return 0;
    }
	if (action) {
		//! [select_slave]
		hal_enterCritical();
		spi_select_slave(&st_masterInst, (spiDesc_t *)p_spi, true);
		//! [select_slave]
	}
	else {
		//! [deselect_slave]
		spi_select_slave(&st_masterInst, (spiDesc_t *)p_spi, false);
		hal_exitCritical();
		//! [deselect_slave]
	}
	return 1;
} //!  [hal_spiSlaveSel]
예제 #24
0
파일: spi.c 프로젝트: areusch/libAVR
bool spi_setup_transfer(SpiTransfer* rq) {

  if (!rq->acknowledgement_try_count &&
      rq->acknowledgement_mode != kSPINoAcknowledgement) {
    rq->acknowledgement_mode = kSPINoAcknowledgement;
  }

  if (!rq->buffer_size_bytes &&
      rq->acknowledgement_mode == kSPINoAcknowledgement) {
    // No data to transfer; xfer complete.

    if (rq->deselect_slave_when_finished)
      spi_select_slave(rq->slave, false);

    if (rq->transfer_complete_callback)
      rq->transfer_complete_callback(rq);

    return false;
  }

  if (rq->receive_offset < rq->buffer_size_bytes &&
      rq->receive_offset + rq->receive_bytes > rq->buffer_size_bytes)
    rq->receive_bytes = rq->buffer_size_bytes - rq->receive_offset;

  spi_select_slave(rq->slave, true);

  rq->slave->control->current_byte = 0;

  // Start the transfer by writing data. The interrupt will finish things off.
  if (rq->buffer_size_bytes) {
    if (rq->use_transmit_constant) {
      *chip_spi_transfer_register(rq->slave->control->port) = rq->transmit_constant;
    } else {
      *chip_spi_transfer_register(rq->slave->control->port) =
        ((uint8_t*) rq->transfer_buffer)[rq->slave->control->current_byte];
    }
  } else {
    *chip_spi_transfer_register(rq->slave->control->port) = rq->acknowledgement_request_byte;
  }
  return true;
}
예제 #25
0
void test_spi_transmission_complete() {
	delay_ms(1);
	spi_enable(SPI0);
	spi_select_slave(SPI0, SPI_SELECTOR_0);
	spi_write(SPI0, 0b01011010);
	spi_write(SPI0, 0b01011011);
	TEST_ASSERT_FALSE(SPI0->SPI_SR & (0x1u << 1));
	TEST_ASSERT_FALSE(SPI0->SPI_SR & (0x1u << 9));
	delay_ms(1);
	TEST_ASSERT_TRUE(SPI0->SPI_SR & (0x1u << 1));
	TEST_ASSERT_TRUE(SPI0->SPI_SR & (0x1u << 9));
}
int main(void)
{
//! [main_start]
	/* Initialize system */
//! [system_init]
	system_init();
//! [system_init]

//! [run_config]
	configure_spi_master();
//! [run_config]
//! [run_callback_config]
	configure_spi_master_callbacks();
//! [run_callback_config]
//! [main_start]

//! [main_use_case]
//! [inf_loop]
	while (true) {
		/* Infinite loop */
		if (!port_pin_get_input_level(BUTTON_0_PIN)) {
			//! [select_slave]
			spi_select_slave(&spi_master_instance, &slave, true);
			//! [select_slave]
			//! [write and read]
			spi_transceive_buffer_job(&spi_master_instance, wr_buffer,rd_buffer,BUF_LENGTH);
			//! [write and read]
			//! [wait]
			while (!transrev_complete_spi_master) {
				/////* Wait for write and read complete */
			}
			//! [wait]
			//! [deselect_slave]
			spi_select_slave(&spi_master_instance, &slave, false);
			//! [deselect_slave]
		}
	}
//! [inf_loop]
//! [main_use_case]
}
예제 #27
0
/**
 * \internal
 * \brief Test: Send data by polling & receive with interrupt.
 *
 * This test sends (writes) an array of data to the slave by polling and
 * receives (reads) the buffer back with interrupt and compares.
 *
 * \param test Current test case.
 */
static void run_buffer_polled_write_interrupt_read_test
	(const struct test_case *test)
{
	uint16_t i;
	uint16_t timeout_cycles;

	/* Skip test if initialization failed */
	test_assert_true(test, spi_init_success,
			"Skipping test due to failed initialization");

	/* Start the test */
	transfer_complete = false;
	timeout_cycles = 1000;
	spi_select_slave(&master, &slave_inst, true);
	spi_read_buffer_job(&slave, rx_buf, BUFFER_LENGTH, 0);
	spi_write_buffer_wait(&master, tx_buf, BUFFER_LENGTH);

	/* Wait until reception completes */
	do {
		timeout_cycles--;
		if (transfer_complete) {
			break;
		}
	} while (timeout_cycles != 0);
	spi_select_slave(&master, &slave_inst, false);

	test_assert_true(test, timeout_cycles > 0,
			"Timeout in reception");

	/* Compare received data with transmitted data */
	if (transfer_complete) {
		for (i = 0; i < BUFFER_LENGTH; i++) {
			test_assert_true(test, tx_buf[i] == rx_buf[i],
					"Bytes differ at buffer index %d : %d != %d",
					i, tx_buf[i], rx_buf[i]);
		}
	}
}
예제 #28
0
파일: rom.c 프로젝트: h4xxel/trollbook
void rom_write(uint32_t address, const uint8_t *buffer, uint32_t size) {
	int i;
	
	while(size >= 256) {
		rom_write_enable();
		
		while(rom_status() & 0x1);
		spi_select_slave(SPI_SLAVE_ROM);
		spi_send_recv(ROM_COMMAND_PAGE_PROGRAM);
		spi_send_recv((address >> 16) & 0xFF);
		spi_send_recv((address >> 8) & 0xFF);
		spi_send_recv(address & 0xFF);
		
		for(i = 0; i < 256; i++)
			spi_send_recv(*buffer++);
		
		spi_select_slave(SPI_SLAVE_NONE);
		
		size -= 256;
		address += 256;
	}
	if(size) {
		rom_write_enable();
		
		while(rom_status() & 0x1);
		spi_select_slave(SPI_SLAVE_ROM);
		spi_send_recv(ROM_COMMAND_PAGE_PROGRAM);
		spi_send_recv((address >> 16) & 0xFF);
		spi_send_recv((address >> 8) & 0xFF);
		spi_send_recv(address & 0xFF);
		
		for(i = 0; i < size; i++)
			spi_send_recv(*buffer++);
		
		spi_select_slave(SPI_SLAVE_NONE);
	}
}
/**
 * \brief Read internal fifo buffer.
 *
 * \param buf the buffer to store the data from the fifo buffer.
 * \param len the amount of data to read.
 */
void ksz8851_fifo_read(uint8_t *buf, uint32_t len)
{
	uint8_t tmpbuf[9];

	spi_select_slave(&ksz8851snl_master, &ksz8851snl_slave, true);

	tmpbuf[0] = FIFO_READ;

	/* Perform SPI transfer. */
	spi_transceive_buffer_wait(&ksz8851snl_master, tmpbuf, tmpbuf, 9);
	spi_read_buffer_wait(&ksz8851snl_master, buf, len, 0xff);

	/* Read CRC (don't care). */
	spi_read_buffer_wait(&ksz8851snl_master, tmpbuf, 4, 0xff);
	len += 4;

	/* Keep internal memory alignment. */
	len &= 3;
	if (len) {
		spi_read_buffer_wait(&ksz8851snl_master, tmpbuf, len, 0xff);
	}

	spi_select_slave(&ksz8851snl_master, &ksz8851snl_slave, false);
}
/**
 * \brief Start to write internal fifo buffer.
 *
 * \param tot_len the total amount of data to write.
 */
void ksz8851_fifo_write_begin(uint32_t tot_len)
{
	uint8_t	outbuf[5];
	static uint8_t frameID = 0;

	spi_select_slave(&ksz8851snl_master, &ksz8851snl_slave, true);

	/* Prepare control word and byte count. */
	outbuf[0] = FIFO_WRITE;
	outbuf[1] = frameID++ & 0x3f;
	outbuf[2] = 0;
	outbuf[3] = tot_len & 0xff;
	outbuf[4] = tot_len >> 8;

	/* Perform SPI transfer. */
	spi_write_buffer_wait(&ksz8851snl_master, outbuf, 5);
}