/* * * mur.sat * * Somewhen in the year 2012, mur.at will have a nano satellite launched * into a low earth orbit (310 km above the surface of our planet). The * satellite itself is a TubeSat personal satellite kit, developed and * launched by interorbital systems. mur.sat is a joint venture of mur.at, * ESC im Labor and realraum. * * Please visit the project hompage at sat.mur.at for further information. * * * Copyright (C) 2012 Bernhard Tittelbach * * This file is part of mur.sat. * * mur.sat is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * mur.sat is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with mur.sat. If not, see . * */ #include #include #include "c1101lib.h" #include "spi.h" #include "usb_rawhid.h" #include "util.h" /**** Helper Functions ****/ #define SPIC1101_MAX_WAIT 21 int16_t spi_c1101_write_byte_ok_get_status(char data) { //~ uint8_t debug_sb[6]; char sb; unsigned int attempts = 0; do { sb = spi_exchange_byte(data); //Note: content of returned StatusByte is actually context depenedant on sent command // i.e. we won't get Fifo Byte count or overflow status on normal command and so on // e.g. we only get TX Fifo Free Byte count while writing to TX Fifo // thus it makes sense to only check for CHIP_RDY here //~ usb_rawhid_send((uint8_t*)"spi byte exchanged ",255); //~ debug_sprint_int16hex(debug_sb, sb); //~ usb_rawhid_send(debug_sb,255); if (attempts++ > SPIC1101_MAX_WAIT) return -1; } while ( SPIC1101_SB_CHIP_NOT_RDY(sb) ); return sb; } // note addresses range from 0x00 to 0x2F for normal registers and 0xF0 to 0xFD for special status registers int16_t spi_c1101_read_register(char address) { char rbyte; if (address < 0x30) address |= 0x80; else address |= 0xC0; spi_cs_enable(); spi_c1101_wait_chip_rdy(); if (spi_c1101_write_byte_ok_get_status(address) < 0) return -1; _delay_ms(10); //FIXME: propably don't need this rbyte = spi_read_byte(); spi_cs_disable(); return rbyte; } // note addresses range from 0x00 to 0x2F for normal registers int16_t spi_c1101_write_register(char address, char byte) { spi_cs_enable(); spi_c1101_wait_chip_rdy(); if (spi_c1101_write_byte_ok_get_status(address & 0x2F) < 0) return -1; _delay_ms(2); if (spi_c1101_write_byte_ok_get_status(byte) < 0) return -1; spi_cs_disable(); return 1; } // note addresses range from 0x30 to 0x3D for command strobes int16_t spi_c1101_strobe_command(char address) { if (spi_c1101_write_byte_ok_get_status(address) < 0) return -1; return 1; } void spi_c1101_dump_registers_to_usb(void) { int c = 0; uint8_t debug_sb[6]; spi_cs_enable(); spi_c1101_wait_chip_rdy(); if (spi_c1101_write_byte_ok_get_status(SPIC1101_ADDR_IOCFG2 | 0x40) < 0) return; usb_rawhid_send((uint8_t*)"dump all 46 registers:",255); for (c=0; c<47; c++) { debug_sprint_int16hex(debug_sb, spi_read_byte()); usb_rawhid_send(debug_sb,255); } spi_cs_disable(); } //note: currently this function reads at most 15 bytes int spi_c1101_read_rxfifo(int leave_num_bytes, char *buffer, int maxlen) { int16_t sb; int num_read = 0; int num_fifo_available = 0; spi_cs_enable(); spi_c1101_wait_chip_rdy(); sb = spi_c1101_write_byte_ok_get_status(SPIC1101_ADDR_FIFO_READ_BURST); if (sb < 0) return -1; num_fifo_available = SPIC1101_SB_FIFO_BYTES_AVAILABLE((char)sb); //note if num_fifo_available == 15 then 15 or more bytes are available //FIXTHIS while (maxlen-- && num_fifo_available - num_read <= leave_num_bytes) { //hope this works !! buffer[num_read++] = spi_read_byte(); } spi_cs_disable(); return num_read; } //note: always check if num_written returned == len given //note: currently this function writes at most 15 bytes int spi_c1101_write_txfifo(char *buffer, int len) { char sb; int num_written = 0; int num_fifo_available = 0; spi_cs_enable(); spi_c1101_wait_chip_rdy(); sb = spi_c1101_write_byte_ok_get_status(SPIC1101_ADDR_FIFO_WRITE_BURST); if (sb < 0) return -1; num_fifo_available = SPIC1101_SB_FIFO_BYTES_AVAILABLE((char)sb); //note if num_fifo_available == 15 then 15 or more bytes are available //FIXTHIS if (num_fifo_available < len) len = num_fifo_available; while (len--) { //hope this works !! spi_write_byte(buffer[num_written++]); } spi_cs_disable(); return num_written; } /**** External Functions ****/ void c1101_init(void) { //reset C1101 spi_c1101_strobe_command(SPIC1101_ADDR_SRES); _delay_ms(100); //flush FIFOs spi_c1101_strobe_command(SPIC1101_ADDR_SFRX); spi_c1101_strobe_command(SPIC1101_ADDR_SFTX); //dump current default values to usb spi_c1101_dump_registers_to_usb(); //enable analog temperature sensor on GDO0 spi_c1101_write_register(SPIC1101_ADDR_IOCFG0, 0x80); // note: for now: assume f_xosc to be 26 Mhz // for ~433.125 Mhz -> freq = 1091741, freq_offset = 0 c1101_setFrequency(1091741,0,15); } // freq: desired_carrier_freq [Hz] *2^16 / f_XOSC // freq_offset: desired frequency offset [Hz] *2^14 / f_XOSC // if_freq: desired intermidiate rx frequency [Hz] *2^10 / f_XOSC void c1101_setFrequency(uint32_t freq, uint8_t freq_offset, uint8_t if_freq) { //make sure we are in idle mode char sb=0; do { sb = c1101_getStatus(); } while (! (SPIC1101_SB_IDLE(sb))); //programm frequency usb_rawhid_send((uint8_t*)"setting frequency",255); spi_c1101_write_register(SPIC1101_ADDR_FREQ0, freq & 0xFF); spi_c1101_write_register(SPIC1101_ADDR_FREQ1, (freq >> 8) & 0xFF); spi_c1101_write_register(SPIC1101_ADDR_FREQ2, (freq >> 16) & 0x3F); //set frequency offset spi_c1101_write_register(SPIC1101_ADDR_FSCTRL0, freq_offset); //spi_c1101_write_register(SPIC1101_ADDR_FSCTRL1, if_freq & 0x1F); //set channel 0 spi_c1101_write_register(SPIC1101_ADDR_CHANNR, 0); } char c1101_getVersion(void) { return spi_c1101_read_register(SPIC1101_ADDR_VERSION); } char c1101_getPartNum(void) { return spi_c1101_read_register(SPIC1101_ADDR_PARTNUM); } uint16_t c1101_measureTemp(void) { uint16_t temp; char ptest_value=0x7F; ptest_value = spi_c1101_read_register(SPIC1101_ADDR_PTEST); spi_c1101_write_register(SPIC1101_ADDR_PTEST, 0xBF); _delay_ms(5); temp = adc_read(ADCMUX_INTERNALTEMP); spi_c1101_write_register(SPIC1101_ADDR_PTEST, ptest_value); return temp; } void c1101_handleStatusByte(char sb) { //on RXFifo Overflow, Flush RX Fifo if (SPIC1101_SB_RXFIFO_OVERFLOW(sb)) { spi_c1101_strobe_command(SPIC1101_ADDR_SFRX); usb_rawhid_send((uint8_t*)"RX fifo flushed",255); } //on TXFifo Overflow, Flush TX Fifo if (SPIC1101_SB_TXFIFO_OVERFLOW(sb)) { spi_c1101_strobe_command(SPIC1101_ADDR_SFTX); usb_rawhid_send((uint8_t*)"TX fifo flushed",255); } } char c1101_getStatus(void) { char sb=0; spi_cs_enable(); spi_c1101_wait_chip_rdy(); sb = spi_c1101_write_byte_ok_get_status(SPIC1101_ADDR_SNOP); spi_cs_disable(); //debug start uint8_t debug_sb[6]; usb_rawhid_send((uint8_t*)"c1101 status:",255); debug_sprint_int16hex(debug_sb, sb); usb_rawhid_send(debug_sb,255); //debug end c1101_handleStatusByte(sb); return sb; } //max len: 64 bytes void c1101_writeTXFifo(char *buffer, unsigned int len) { //check TXBYTES.NUM_TXBYTES // never write more bytes than avaiblabe or doom ensues } //max returned: 64 bytes int c1101_readRXFifo(char *buffer) { //check RXBYTES.NUM_RXBYTES // never read more bytes than avaiblabe or we will read garbage //note: if RX transmission fills fifo buffer at exact same time as last RX Fifo Bit is read via SPI, Fifo Pointer will not be properly updated // and last read byte will be duplicated. // thus: don't last avialable FIFO Bytes unless we can be sure that it will be the last byte of a packet and we can be sure that a following duplicated byte is actually an Fifo duplication and not an actually recieved byte ! return 0; }