Beispiel #1
0
// note 1: extracted to function & hand-optimized because avr-gcc *duh*
// note 2: unroll to get even faster code:
//   256 loop itself takes 3 clocks [2 words], non-256 one takes 4 clocks [3 words],
//   inlined spi_recv() takes *at least* (no SPI wait) 5 clocks [5 words],
//   ASM_ST_INC is 2 clocks [1 word]; it follows that the loop takes (no SPI wait):
//   with 2x unrolling: (the default)
//     256 * [(5+2) *  2 + 3] = 4352 clocks; (5+1)*2+2  = 14 words
//   with 4x unrolling: (+6% for ~+25 bytes)
//     128 * [(5+2) *  4 + 4] = 4096 clocks; (5+1)*4+3  = 27 words
//   with 8x unrolling: (another +6% for ~+50 bytes)
//     64 *  [(5+2) *  8 + 4] = 3840 clocks; (5+1)*8+3  = 51 words
//   with 16x unrolling: (+3% for ~+100 bytes)
//     32 *  [(5+2) * 16 + 4] = 3712 clocks; (5+1)*16+3 = 99 words
//   further unrolling is subject to diminishing results, with maximum speed
//   at full unroll being only 3588 clocks, i.e. 3% faster than 16x unroll
//
//__attribute__ ((noinline))
void _spi_recv_block( uint8_t* buf ) {
    uint8_t j = 0;
#ifdef SD_DONT_UNROLL_RECV_BLOCK
    do {
        ASM_ST_INC( buf,  spi_recv() ); // *(buf++) = spi_recv();
        ASM_ST_INC( buf,  spi_recv() );
    } while ( ++j ); // 512 spi_recv() executions total
#else
#define SD_UNROLL_REPEAT8(x)  x; x; x; x; x; x; x; x
    do {
        SD_UNROLL_REPEAT8( ASM_ST_INC( buf,  spi_recv() ) );
    } while ( ++j < 64 ); // 512 spi_recv() executions total
#endif
}
Beispiel #2
0
void
proto_callback (uint8_t cmd, uint8_t size, uint8_t *args)
{
    /* TODO: command to select a slave. */
#define c(cmd, size) (cmd << 8 | size)
    switch (c (cmd, size))
      {
      case c ('z', 0):
	utils_reset ();
	break;
      case c ('s', 1):
	spi_send (args[0]);
	break;
      case c ('r', 0):
	proto_send1b ('R', spi_recv ());
	break;
      case c ('r', 1):
	proto_send1b ('R', spi_send_and_recv (args[0]));
	break;
      default:
	proto_send0 ('?');
	return;
      }
    proto_send (cmd, size, args);
#undef c
}
Beispiel #3
0
static int atben_buf_read(void *handle, void *buf, int size)
{
	struct atben_dsc *dsc = handle;
	uint8_t len, i;

	spi_begin(dsc);
	spi_send(dsc, AT86RF230_BUF_READ);
	len = spi_recv(dsc);
	len++; /* LQI */
	if (len > size)
		len = size;
	for (i = 0; i != len; i++)
		*(uint8_t *) buf++ = spi_recv(dsc);
	spi_end(dsc);
	return len;
}
Beispiel #4
0
static void
tmp121temp_refresh(struct sysmon_envsys *sme, envsys_data_t *edata)
{
	struct tmp121temp_softc *sc = sme->sme_cookie;
	uint16_t		reg;
	int16_t			sreg;
	int			val;

	if (spi_recv(sc->sc_sh, 2, (uint8_t *)&reg) != 0) {
		edata->state = ENVSYS_SINVALID;
		return;
	}

	sreg = (int16_t)be16toh(reg);

	/*
	 * convert to uK:
	 *
	 * TMP121 bits:
	 * D15		: sign bit
	 * D14-D3	: data (D14 is MSB)
	 * D2-D0	: zero
	 *
	 * The data is represented in units of 0.0625 deg C.
	 */
	sreg >>= 3;
	val = sreg * 62500 + 273150000;

	edata->value_cur = val;
	edata->state = ENVSYS_SVALID;
}
Beispiel #5
0
static inline uint8_t spi_3366_read(const uint8_t addr)
{
	spi_send(addr);
	delay_us(160); // t_SRAD
	uint8_t data = spi_recv();
	delay_us(20);
	return data;
}
Beispiel #6
0
void sd_preinit( void ) {
    spi_assert_SS();
	for( uint8_t i = SD_INIT_IDLE_CYCLES; i > 0; i-- ) {
        sd_debug_verbose_printf( "~" );
		spi_recv();
    }
    sd_debug_verbose_printf( "|\n\r" );
    spi_deassert_SS();
}
Beispiel #7
0
static uint8_t atben_reg_read(void *handle, uint8_t reg)
{
	struct atben_dsc *dsc = handle;
	uint8_t res;

	spi_begin(dsc);
	spi_send(dsc, AT86RF230_REG_READ | reg);
	res = spi_recv(dsc);
	spi_end(dsc);
	return res;
}
Beispiel #8
0
static uint8_t atben_sram_read(void *handle, uint8_t addr)
{
	struct atben_dsc *dsc = handle;
	uint8_t res;

	spi_begin(dsc);
	spi_send(dsc, AT86RF230_SRAM_READ);
	spi_send(dsc, addr);
	res = spi_recv(dsc);
	spi_end(dsc);
	return res;
}
Beispiel #9
0
// @return  response returned from command, or SPI_EMPTY_BYTE (0xFF) if failed
// note 1: this code assumes a regular 512-byte block since SDHC allows only this
// note 2: this function is slower than sd_readSingleBlockHC
uint8_t sd_readPartialBlockHC( uint8_t addr3, uint8_t addr2, uint8_t addr1, uint8_t addr0, uint8_t* buf, uint16_t offset, uint16_t len ) {
    uint8_t ret = sd_command( SD_READ_SINGLE_BLOCK, addr3, addr2, addr1, addr0 );
    if ( ret != SD_RET_READY ) {
        sd_debug_printf( "RET: not READY; [0x%02hhx] received\n\r", ret );
        return SPI_EMPTY_BYTE;
    }
    spi_assert_SS();
    for( uint8_t i = SD_SPI_RESPONSE_WAIT_MAX; i > 0; i-- ) {
        *buf = spi_recv();
        if ( *buf == SPI_EMPTY_BYTE  ) {
            continue;
        }
        if ( *buf != SD_DATA_TOKEN ) {
            spi_deassert_SS();
            sd_debug_printf( "RET: invalid token received\n\r" );
            return SPI_EMPTY_BYTE;
        }
        uint16_t i = 0, end = offset + len;
        for( ; i < offset; i++ ) {
            spi_recv();
        }
        for( ; i < end; i++ ) {
            *(buf++) = spi_recv();
        }
        for( ; i < SD_HC_BLOCK_LENGTH; i++ ) {
            spi_recv();
        }
        // CRC values are ignored outside of debug mode; split to avoid comp. warnings
#ifdef SD_DEBUG_VERBOSE
        uint8_t crc1 = spi_recv();
        uint8_t crc2 = spi_recv();
        sd_debug_verbose_printf( "CRC: 0x%02hhx %02hhx\n\r", crc1, crc2 );
#else
        spi_recv();
        spi_recv();
#endif
        spi_recv(); // required 8 clock cooldown
        return ret;
    }
    spi_deassert_SS();
    sd_debug_printf( "RET: busy\n\r" );
    return SPI_EMPTY_BYTE;
}
Beispiel #10
0
uint8_t
flash_init (void)
{
    uint8_t rsp[3];
    uint8_t res;

    AC_FLASH_PORT |= _BV(AC_FLASH_BIT_SS);
    AC_FLASH_DDR |= _BV(AC_FLASH_BIT_SS);

    /* send the read-ID instruction. */
    spi_init (SPI_MASTER, SPI_CPOL_FALLING | SPI_CPHA_SETUP, SPI_MSB_FIRST,
	      SPI_FOSC_DIV16);

    FLASH_CS_ENABLE;
    spi_send (FLASH_SST_CMD_READ_ID);
    rsp[0] = spi_recv ();
    rsp[1] = spi_recv ();
    rsp[2] = spi_recv ();
    FLASH_CS_DISABLE;

    switch (rsp[0])
      {
      case FLASH_SST_MANUFACTURER_ID:
	flash_sst_init ();
	flash_init_sst ();
	res = 1;
	break;
      case FLASH_AT_MANUFACTURER_ID:
	flash_at_init ();
	flash_init_at ();
	res = 1;
	break;
      default:
	res = 0;
      }
    return res;
}
Beispiel #11
0
int main (void) {
	init();
	led_on();
	uart_str("Hello!\r\n");
	spi_slave();
	led_off();
	while (1) {
		switch (spi_recv()) {
			case 0: break;
			case 1:
				// CPU wants to read a value. this means we are now the master, to transfer the value back.
				spi_master();
				spi_send(uart_read());
				spi_slave();
				break;
			case 2:
				// CPU wrote a value. Output it to serial.
				uart_write(spi_recv());
				break;
			default:
				break;
		}
	}
}
Beispiel #12
0
/*****************************************************************************
* 函 数 名  : spiDevDetect
*
* 功能描述  : 动态探测SPI总线上接入的设备类型,验证SPI总线驱动
*
* 输入参数  :
* 输出参数  :
*
* 返 回 值  :
*
* 其它说明  :
*
*****************************************************************************/
s32 spi_dev_detect( eSpiDevType *devType )
{
    u16 ucCmdRDID = SPI_DEV_CMD_RDID;
    u32 ulRecv = 0;

    /*cprintf("\r\nspiDevDetect begin!" );*/
    if(NULL == devType)
    {
        cprintf("\r\nPARA *devType is NULL!");
        return ERROR;
    }

    /* EEPROM对该命令不支持,会收不到数据超时退出 */
    if(OK != spi_recv(SPI_NO_DEV, SPI_CS_DEV, (u16*)&ulRecv, 3, &ucCmdRDID, 1))
    {
        cprintf("\r\nread ID err");
        *devType = E_SPI_DEV_TYPE_EEPROM;

        return OK;
    }

    cprintf("\r\nID: %x", ulRecv);

    /* EEPROM不支持该命令,会返回全0或全1 */
    if(0 != ulRecv && 0xFFFFFF != ulRecv)
    {
        *devType = E_SPI_DEV_TYPE_SFLASH;
    }
    else
    {
        *devType = E_SPI_DEV_TYPE_EEPROM;
    }
    cprintf("\r\ndevType is :  @ %x", *devType);

    return OK;

}
Beispiel #13
0
// @return  response returned from command, or SPI_EMPTY_BYTE (0xFF) if failed
// note: this code assumes a regular 512-byte block since SDHC allows only this
// pass len == 0 to read all 512 bytes into buf
uint8_t sd_readSingleBlockHC( uint8_t addr3, uint8_t addr2, uint8_t addr1, uint8_t addr0, uint8_t* buf ) {
    uint8_t ret = sd_command( SD_READ_SINGLE_BLOCK, addr3, addr2, addr1, addr0 );
    if ( ret != SD_RET_READY ) {
        sd_debug_printf( "RET: not READY; [0x%02hhx] received\n\r", ret );
        return SPI_EMPTY_BYTE;
    }
    spi_assert_SS();
    for( uint8_t i = SD_SPI_RESPONSE_WAIT_MAX; i > 0; i-- ) {
        *buf = spi_recv();
        if ( *buf == SPI_EMPTY_BYTE  ) {
            continue;
        }
        if ( *buf != SD_DATA_TOKEN ) {
            spi_deassert_SS();
            sd_debug_printf( "RET: invalid token received\n\r" );
            return SPI_EMPTY_BYTE;
        }
        _spi_recv_block( buf );
        // CRC values are ignored outside of debug mode; split to avoid comp. warnings
#ifdef SD_DEBUG_VERBOSE
        uint8_t crc1 = spi_recv();
        uint8_t crc2 = spi_recv();
        sd_debug_verbose_printf( "CRC: 0x%02hhx %02hhx\n\r", crc1, crc2 );
#else
        spi_recv();
        spi_recv();
#endif
        sd_debug_verbose_printf( "CRC: 0x%02hhx %02hhx\n\r", crc1, crc2 );
        // do a CRC check if you're masochistic (or have a GHz-ish CPU)
        spi_recv(); // required 8 clock cooldown
        return ret;
    }
    spi_deassert_SS();
    sd_debug_printf( "RET: busy\n\r" );
    return SPI_EMPTY_BYTE;
}
Beispiel #14
0
int main(void)
{
	// set clock prescaler for 8MHz
	CLKPR = 0x80;
	CLKPR = 0x01;

	cli();

	power_all_disable();
	power_spi_enable();
	power_timer1_enable();
	set_sleep_mode(SLEEP_MODE_IDLE);

	pins_init();

	delay_ms(345); // arbitrary

	uint8_t dpi = 0x0f; // default to 800
	if (!(PIND & (1<<0))) // if left is pressed at boot
		dpi = 0xff; // set to 12800

	pmw3366_init(dpi);
	nrf24_init();

	// button stuff
	// previous debounced state
	uint8_t btn_prev = ~(PIND);
	// time (in 125us) button has been unpressed.
	// consider button to be released if this time exceeds DEBOUNCE_TIME.
	uint8_t btn_time[3] = {0, 0, 0};

	// absolute positions. relies on integer overflow
	union motion_data x = {0}, y = {0};

	// wheel stuff
	uint8_t whl_prev_same = 0; // what A was the last time A == B
	uint8_t whl_prev_diff = 0; // what A was the last time A != B
	// absolute scroll position. relies on integer overflow
	int8_t whl = 0;

	// begin burst mode for 3366
	spi_set3366mode();
	SS_3366_LOW;
	spi_3366_write(0x50, 0x00);
	SS_3366_HIGH;

	// set up timer1 to set OCF0A in TIFR0 every 1ms
	TCCR1A = 0x00;
	TCCR1B = 0x09; // CTC, 8MHz
	OCR1A = 7999; // main loop nominal period (7999 + 1) / 8MHz = 1ms
	OCR1B = 320; // timing of when to read burst mode data from sensor
	OCR1C = 800; // timing of when to load nrf24l01+ with data

	// let receiver know if it's the first time sending data, so that it
	// can reset the reference for absolute position and that there's no
	// jump when rebooting the mouse
	// uint8_t first = 0x80; // transmitted as MSB with button data below.

	// when sync reaches 0, always send a packet with bit 6 in btn set, to
	// tell the receiver to calculate the timing offset.
	// when sync reaches 1, always send a packet requesting ACK to load the
	// timing offset
	// i.e. when it overflows, so 256ms periodicity.

	// when sync reaches 0, afk increments.
	// afk is cleared by any motion or button press.
	// when afk reaches AFK_TIMEOUT, go into powerdown mode.
	for (uint8_t first = 0x80, sync = 0, afk = 0; ; first = 0, sync++) {
		// sync to 1ms intervals using timer1
	//	if (TIFR1 & (1<<OCF1A)) PORTD |= (1<<6);
		TIMSK1 |= (1<<OCIE1A);
		sei(); sleep_mode(); cli();
		TIMSK1 &= ~(1<<OCIE1A);
		TIFR1 |= (1<<OCF1A); TIFR1 |= (1<<OCF1B); TIFR1 |= (1<<OCF1C);

		// begin burst mode read
		spi_set3366mode();
		SS_3366_LOW;
		spi_send(0x50);
		// do stuff here instead of busy waiting for 35us

		// read wheel
		int8_t dwhl = 0;
		const uint8_t whl_a = WHL_A_IS_HIGH;
		const uint8_t whl_b = WHL_B_IS_HIGH;
	//	if (whl_a == whl_b) {
	//		if (whl_a != whl_prev_same) {
	//			dwhl = 2 * (whl_a ^ whl_prev_diff) - 1;
	//			whl += dwhl;
	//			whl_prev_same = whl_a;
	//		}
	//	} else
	//		whl_prev_diff = whl_a;
		if (whl_a != whl_b)
			whl_prev_diff = whl_a;
		else if (whl_a != whl_prev_same) {
			dwhl = 2 * (whl_a ^ whl_prev_diff) - 1;
			whl += dwhl;
			whl_prev_same = whl_a;
		}

		// read buttons
		/*
		PIND 0 EIFR 0: low, no edges -> is low
		PIND 0 EIFR 1: low, edge -> is low
		PIND 1 EIFR 0: high, no edges -> always high during last 1ms
		PIND 1 EIFR 1: high, edge -> low at some point in the last 1ms
		*/
		const uint8_t btn_unpressed = PIND & ~(EIFR);
		EIFR = 0b00000111; // clear EIFR
		// manual loop debouncing for every button
		uint8_t btn_dbncd = 0x00;
		#define DEBOUNCE(index) \
		if ((btn_prev & (1<<index)) && (btn_unpressed & (1<<index))) { \
			btn_time[index]++; \
			if (btn_time[index] < DEBOUNCE_TIME) \
				btn_dbncd |= (1<<index); \
		} else { \
			btn_time[index] = 0; \
			btn_dbncd |= (~btn_unpressed) & (1<<index); \
		}

		DEBOUNCE(0);
		DEBOUNCE(1);
		DEBOUNCE(2);
		#undef DEBOUNCE

		// wait until 35us have elapsed since spi_send(0x50)
	//	if (TIFR1 & (1<<OCF1B)) PORTD |= (1<<6);
		TIMSK1 |= (1<<OCIE1B);
		sei(); sleep_mode(); cli();
		TIMSK1 &= ~(1<<OCIE1B);

		union motion_data dx, dy;
		spi_send(0x00); // motion, not used
		spi_send(0x00); // observation, not used
		dx.lo = spi_recv();
		dx.hi = spi_recv();
		dy.lo = spi_recv();
		dy.hi = spi_recv();
		SS_3366_HIGH;

		x.all += dx.all;
		y.all += dy.all;

		if (sync == 0) afk++;
		const uint8_t changed = (btn_dbncd != btn_prev) || dx.all || dy.all || dwhl;
		if (changed) afk = 0;

		if (changed || (sync <= 1)) {
			btn_prev = btn_dbncd;
			// W_TX_PAYLOAD if sync == 1, W_TX_PAYLOAD_NOACK otherwise
			const uint8_t mode = (sync == 1) ? 0b10100000 : 0b10110000;
			// send miscellaneous info using top bits of btn byte
			uint8_t btn_send = btn_dbncd | first; // first is either 0x80 or 0
			if (sync == 0) btn_send |= 0x40;

			// try to transmit at the same time every frame
	//		if (TIFR1 & (1<<OCF1C)) {PORTD |= (1<<6);}
			TIMSK1 |= (1<<OCIE1C);
			sei(); sleep_mode(); cli();
			TIMSK1 &= ~(1<<OCIE1C);

			spi_setnrf24mode();
			SS_NRF24_LOW;
			spi_send(0x20 | 0x07); // STATUS
			spi_send(0b01110000); // clear IRQ
			SS_NRF24_HIGH;
			SS_NRF24_LOW;
			spi_send(0b11100001); // flush tx
			SS_NRF24_HIGH;
			SS_NRF24_LOW;
			spi_send(0b11100010); // flush rx
			SS_NRF24_HIGH;

			SS_NRF24_LOW;
			spi_send(mode);
			spi_send(btn_send);
			spi_send(x.lo);
			spi_send(x.hi);
			spi_send(y.lo);
			spi_send(y.hi);
			spi_send(whl);
			SS_NRF24_HIGH;

			// pulse CE to transmit
			CE_HIGH;
			delay_us(12);
			CE_LOW;

			if (sync == 1) { // get ack payload of timing offset
				delay_us(400);
				if (IRQ_IS_LOW) {
					// recycle motion_data union for timing
					union motion_data offset;
					SS_NRF24_LOW;
					spi_send(0b01100001);
					offset.lo = spi_recv();
					offset.hi = spi_recv();
					SS_NRF24_HIGH;
					// shift TCNT1 by the offset, plus a
					// little more because of the time it
					// takes to add stuff to TCNT1.
					TCNT1 += offset.all + 11;
				}
			}
		}

		// power down if afk
		if (afk > AFK_TIMEOUT) {
			// enable external interrupts on INT0/1/2/3, PCINT0
			EIMSK = 0b00000111;
			PCICR = 0x01;
			// go power down mode; wake up on interrupt
			set_sleep_mode(SLEEP_MODE_PWR_DOWN);
			sei(); sleep_mode(); cli();
			// disable external interrupts
			PCICR = 0;
			EIMSK = 0;
			// restore state
			set_sleep_mode(SLEEP_MODE_IDLE);
			sync = 0;
			afk = 0;
		}
	}
}
Beispiel #15
0
// @return  first byte of returned response, or SPI_EMPTY_BYTE (0xFF) if failed
uint8_t sd_commandEx( uint8_t cmd, uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t arg3, uint8_t crc, uint8_t* retBuf ) {
    sd_debug_verbose_printf( "CMD: %hhu ARG: 0x%02hhx %02hhx %02hhx %02hhx CRC: 0x%02hhx\n\r",
                  cmd, arg0, arg1, arg2, arg3, crc );
    spi_assert_SS();
	spi_send( cmd | 0x40 );
	spi_send( arg0 );
	spi_send( arg1 );
	spi_send( arg2 );
	spi_send( arg3 );
	spi_send( crc );

    uint8_t r;
    bool allowBusyByte = false;
    switch( cmd ) {
        case SD_SEND_IF_COND: // CMD8 // R7
        case SD_READ_OCR: // CMD58 // R3
            r = 5;
            break;
        case SD_SEND_STATUS: // CMD13
        //case SD_STATUS: // ACMD13 // handled by case above
            r = 2; // R2
            break;
        case SD_STOP_TRANSMISSION: // CMD12
        case SD_SET_WRITE_PROT: // CMD28
        case SD_CLR_WRITE_PROT: // CMD29
        case SD_ERASE: // CMD38
            allowBusyByte = true;  // R1b
        default: // R1
            r = 1;
            break;
    }

    for( uint8_t i = SD_SPI_RESPONSE_WAIT_MAX; i > 0; i-- ) {
        retBuf[0] = spi_recv();
        if ( retBuf[0] == SPI_EMPTY_BYTE  ) {
            continue;
        }
        if ( allowBusyByte ) { // implies r == 1
            retBuf[1] = spi_recv();
            if ( !retBuf[1] ) { // busy; don't wait, just return; caller should wait himself
                spi_deassert_SS();
                sd_debug_printf( "RET: busy\n\r" );
                return SD_COMMAND_ERROR; // == SPI_EMPTY_BYTE
            } // else !busy - we already did the wait
        } else {
            for( uint8_t j = 1; j < r; j++ ) {
                retBuf[j] = spi_recv();
            }
        }
        spi_recv(); // req. 8 cycles wait = 1 SPI output byte
	    spi_deassert_SS();
        sd_debug_verbose_printf( "RET: 0x%02hhx 0x%02hhx 0x%02hhx 0x%02hhx 0x%02hhx\n\r",
                      retBuf[0],
              r > 1 ? retBuf[1] : 0xFF,
              r > 2 ? retBuf[2] : 0xFF,
              r > 3 ? retBuf[3] : 0xFF,
              r > 4 ? retBuf[4] : 0xFF );
        return retBuf[0];
    }
    spi_deassert_SS();
    sd_debug_printf( "RET: error: response timeout\n\r" );
    return SD_COMMAND_ERROR; // == SPI_EMPTY_BYTE
}