From 5514d168ab7fb6fb8d11238f4a381029b043c124 Mon Sep 17 00:00:00 2001 From: Nick Foster Date: Tue, 10 Aug 2010 14:16:48 -0700 Subject: Interrupt-driven I2C. txrx_uhd uses async i2c for comms. --- firmware/microblaze/apps/txrx_uhd.c | 67 ++++++++++--- firmware/microblaze/lib/i2c.c | 184 +++++++++++++++++++++++++++++++++++- firmware/microblaze/lib/i2c.h | 18 ++++ firmware/microblaze/lib/u2_init.c | 14 ++- 4 files changed, 259 insertions(+), 24 deletions(-) diff --git a/firmware/microblaze/apps/txrx_uhd.c b/firmware/microblaze/apps/txrx_uhd.c index f0a9702be..30c1a13b4 100644 --- a/firmware/microblaze/apps/txrx_uhd.c +++ b/firmware/microblaze/apps/txrx_uhd.c @@ -172,6 +172,25 @@ void handle_udp_data_packet( #define OTW_GPIO_BANK_TO_NUM(bank) \ (((bank) == USRP2_DIR_RX)? (GPIO_RX_BANK) : (GPIO_TX_BANK)) + //setup the output data +static usrp2_ctrl_data_t ctrl_data_out; +static struct socket_address i2c_src, i2c_dst; + +static volatile bool i2c_done = false; +void i2c_read_done_callback(void) { + //printf("I2C read done callback\n"); + i2c_async_data_ready(ctrl_data_out.data.i2c_args.data); + i2c_done = true; + i2c_register_callback(0); +} + +void i2c_write_done_callback(void) { + //printf("I2C write done callback\n"); + i2c_done = true; + i2c_register_callback(0); +} + + void handle_udp_ctrl_packet( struct socket_address src, struct socket_address dst, unsigned char *payload, int payload_len @@ -181,9 +200,9 @@ void handle_udp_ctrl_packet( uint32_t ctrl_data_in_id = ctrl_data_in->id; //ensure that the protocol versions match - if (payload_len >= sizeof(uint32_t) && ctrl_data_in->proto_ver != USRP2_FW_COMPAT_NUM){ - printf("!Error in control packet handler: Expected compatibility number %d, but got %d\n", - USRP2_FW_COMPAT_NUM, ctrl_data_in->proto_ver + if (payload_len >= sizeof(uint32_t) && ctrl_data_in->proto_ver != USRP2_PROTO_VERSION){ + printf("!Error in control packet handler: Expected protocol version %d, but got %d\n", + USRP2_PROTO_VERSION, ctrl_data_in->proto_ver ); ctrl_data_in_id = USRP2_CTRL_ID_WAZZUP_BRO; } @@ -197,11 +216,9 @@ void handle_udp_ctrl_packet( } //setup the output data - usrp2_ctrl_data_t ctrl_data_out = { - .proto_ver = USRP2_FW_COMPAT_NUM, - .id=USRP2_CTRL_ID_HUH_WHAT, - .seq=ctrl_data_in->seq - }; + ctrl_data_out.proto_ver = USRP2_PROTO_VERSION; + ctrl_data_out.id=USRP2_CTRL_ID_HUH_WHAT; + ctrl_data_out.seq=ctrl_data_in->seq; //handle the data based on the id switch(ctrl_data_in_id){ @@ -212,6 +229,7 @@ void handle_udp_ctrl_packet( case USRP2_CTRL_ID_WAZZUP_BRO: ctrl_data_out.id = USRP2_CTRL_ID_WAZZUP_DUDE; memcpy(&ctrl_data_out.data.ip_addr, get_ip_addr(), sizeof(struct ip_addr)); + send_udp_pkt(USRP2_UDP_CTRL_PORT, src, &ctrl_data_out, sizeof(ctrl_data_out)); break; /******************************************************************* @@ -232,6 +250,7 @@ void handle_udp_ctrl_packet( ctrl_data_out.data.spi_args.data = result; ctrl_data_out.id = USRP2_CTRL_ID_OMG_TRANSACTED_SPI_DUDE; } + send_udp_pkt(USRP2_UDP_CTRL_PORT, src, &ctrl_data_out, sizeof(ctrl_data_out)); break; /******************************************************************* @@ -239,26 +258,38 @@ void handle_udp_ctrl_packet( ******************************************************************/ case USRP2_CTRL_ID_DO_AN_I2C_READ_FOR_ME_BRO:{ uint8_t num_bytes = ctrl_data_in->data.i2c_args.bytes; - i2c_read( + i2c_register_callback(i2c_read_done_callback); + /*i2c_read( ctrl_data_in->data.i2c_args.addr, ctrl_data_out.data.i2c_args.data, num_bytes + );*/ + i2c_async_read( + ctrl_data_in->data.i2c_args.addr, + num_bytes ); + i2c_src = src; + i2c_dst = dst; ctrl_data_out.id = USRP2_CTRL_ID_HERES_THE_I2C_DATA_DUDE; ctrl_data_out.data.i2c_args.bytes = num_bytes; } + //send_udp_pkt(USRP2_UDP_CTRL_PORT, src, &ctrl_data_out, sizeof(ctrl_data_out)); //TODO: NO break; case USRP2_CTRL_ID_WRITE_THESE_I2C_VALUES_BRO:{ uint8_t num_bytes = ctrl_data_in->data.i2c_args.bytes; - i2c_write( + i2c_register_callback(i2c_write_done_callback); + i2c_async_write( ctrl_data_in->data.i2c_args.addr, ctrl_data_in->data.i2c_args.data, num_bytes ); + i2c_src = src; + i2c_dst = dst; ctrl_data_out.id = USRP2_CTRL_ID_COOL_IM_DONE_I2C_WRITE_DUDE; ctrl_data_out.data.i2c_args.bytes = num_bytes; } + //send_udp_pkt(USRP2_UDP_CTRL_PORT, src, &ctrl_data_out, sizeof(ctrl_data_out)); //TODO: NO break; /******************************************************************* @@ -287,6 +318,7 @@ void handle_udp_ctrl_packet( } ctrl_data_out.id = USRP2_CTRL_ID_OMG_POKED_REGISTER_SO_BAD_DUDE; + send_udp_pkt(USRP2_UDP_CTRL_PORT, src, &ctrl_data_out, sizeof(ctrl_data_out)); break; case USRP2_CTRL_ID_PEEK_AT_THIS_REGISTER_FOR_ME_BRO: @@ -309,13 +341,15 @@ void handle_udp_ctrl_packet( } ctrl_data_out.id = USRP2_CTRL_ID_WOAH_I_DEFINITELY_PEEKED_IT_DUDE; + send_udp_pkt(USRP2_UDP_CTRL_PORT, src, &ctrl_data_out, sizeof(ctrl_data_out)); break; default: ctrl_data_out.id = USRP2_CTRL_ID_HUH_WHAT; + send_udp_pkt(USRP2_UDP_CTRL_PORT, src, &ctrl_data_out, sizeof(ctrl_data_out)); } - send_udp_pkt(USRP2_UDP_CTRL_PORT, src, &ctrl_data_out, sizeof(ctrl_data_out)); + } /* @@ -441,8 +475,7 @@ main(void) print_mac_addr(ethernet_mac_addr()->addr); newline(); print_ip_addr(get_ip_addr()); newline(); - printf("FPGA compatibility number: %d\n", USRP2_FPGA_COMPAT_NUM); - printf("Firmware compatibility number: %d\n", USRP2_FW_COMPAT_NUM); + printf("Control protocol version: %d\n", USRP2_PROTO_VERSION); ethernet_register_link_changed_callback(link_changed_callback); ethernet_init(); @@ -481,10 +514,16 @@ main(void) buffer_irq_handler(0); + if(i2c_done) { + i2c_done = false; + send_udp_pkt(USRP2_UDP_CTRL_PORT, i2c_src, &ctrl_data_out, sizeof(ctrl_data_out)); + //printf("Sending UDP packet from main loop for I2C...\n"); + } + int pending = pic_regs->pending; // poll for under or overrun if (pending & PIC_UNDERRUN_INT){ - //dbsm_handle_tx_underrun(&dsp_tx_sm); + dbsm_handle_tx_underrun(&dsp_tx_sm); pic_regs->pending = PIC_UNDERRUN_INT; // clear interrupt putchar('U'); } diff --git a/firmware/microblaze/lib/i2c.c b/firmware/microblaze/lib/i2c.c index 3f738733b..b60a05fcc 100644 --- a/firmware/microblaze/lib/i2c.c +++ b/firmware/microblaze/lib/i2c.c @@ -19,12 +19,15 @@ #include "i2c.h" #include "memory_map.h" #include "stdint.h" +#include +#include "pic.h" +#include "nonstdio.h" #define MAX_WB_DIV 4 // maximum wishbone divisor (from 100 MHz MASTER_CLK) // prescaler divisor values for 100 kHz I2C [uses 5 * SCLK internally] -#define PRESCALER(wb_div) (((MASTER_CLK_RATE/(wb_div)) / (5 * 100000)) - 1) +#define PRESCALER(wb_div) (((MASTER_CLK_RATE/(wb_div)) / (5 * 400000)) - 1) static uint16_t prescaler_values[MAX_WB_DIV+1] = { 0xffff, // 0: can't happen @@ -34,6 +37,18 @@ static uint16_t prescaler_values[MAX_WB_DIV+1] = { PRESCALER(4), // 4: 25 MHz }; +//asynchronous (interrupt-driven) i2c state variables +volatile uint8_t i2c_buf[17]; //tx/rx data transfer buffer +volatile uint8_t *i2c_bufptr = i2c_buf; //ptr to current position +volatile uint8_t i2c_len = 0; //length remaining in current transfer +volatile i2c_state_t i2c_state = I2C_STATE_IDLE; //current I2C transfer state +i2c_dir_t i2c_dir; //I2C transfer direction + +volatile void (*i2c_callback)(void); //function pointer to i2c callback to be called when transaction is complete + +static void i2c_irq_handler(unsigned irq); +inline void i2c_async_err(void); + void i2c_init(void) { @@ -47,9 +62,10 @@ i2c_init(void) i2c_regs->prescaler_lo = prescaler_values[wb_div] & 0xff; i2c_regs->prescaler_hi = (prescaler_values[wb_div] >> 8) & 0xff; - i2c_regs->ctrl = I2C_CTRL_EN; // enable core + i2c_regs->ctrl = I2C_CTRL_EN; //| I2C_CTRL_IE; // enable core - // FIXME interrupt driven? + // FIXME interrupt driven? + pic_register_handler(IRQ_I2C, i2c_irq_handler); } static inline void @@ -107,7 +123,7 @@ i2c_write(unsigned char i2c_addr, const unsigned char *buf, unsigned int len) i2c_regs->data = (i2c_addr << 1) | 0; // 7 bit address and write bit (0) // generate START and write addr (and maybe STOP) - i2c_regs->cmd_status = I2C_CMD_WR | I2C_CMD_START | (len == 0 ? I2C_CMD_STOP : 0); + i2c_regs->cmd_status = I2C_CMD_WR | I2C_CMD_START | (len == 0 ? I2C_CMD_STOP : 0); if (!wait_chk_ack()) goto fail; @@ -124,4 +140,162 @@ i2c_write(unsigned char i2c_addr, const unsigned char *buf, unsigned int len) return false; } - +static void i2c_irq_handler(unsigned irq) { +//i2c state machine. + + //printf("I2C irq handler\n"); + //first let's make sure nothing is f'ed up + if(((i2c_regs->cmd_status & I2C_ST_RXACK) != 0) && i2c_dir == I2C_DIR_WRITE) { //we got a NACK and we didn't send it + printf("\tNACK received\n"); + i2c_async_err(); + return; + }// else printf("\tACK received, proceeding\n"); + + if(i2c_regs->cmd_status & I2C_ST_AL) { + printf("\tArbitration lost!\n"); + i2c_async_err(); + return; + } + + if(i2c_regs->cmd_status & I2C_ST_TIP) { + //printf("\tI2C still busy in interrupt\n"); + return; + } + + //now decide what to do + switch(i2c_state) { + + case I2C_STATE_IDLE: + //this is an error. in idle state, we shouldn't be transferring data, and the fact that the IRQ fired is terrible bad. + printf("AAAAAHHHHH INTERRUPT IN THE IDLE STATE AAAHHHHHHHHH\n"); + i2c_async_err(); + break; + + case I2C_STATE_CONTROL_BYTE_SENT: //here we've sent the control byte, and we're either clocking data in or out now, but we haven't received a byte yet. + case I2C_STATE_DATA: //here we're sending/receiving data and if we're receiving there's data in the data reg + + //if(i2c_state == I2C_STATE_DATA) printf("\tI2C in state DATA with dir=%d and len=%d\n", i2c_dir, i2c_len); + //else printf("\tI2C in state CONTROL_BYTE_SENT with dir=%d and len=%d\n", i2c_dir, i2c_len); + + if(i2c_dir == I2C_DIR_READ) { + if(i2c_state == I2C_STATE_DATA) *(i2c_bufptr++) = i2c_regs->data; + //printf("\tRead %x\n", *(i2c_bufptr-1)); + //set up another data byte + if(i2c_len > 1) //only one more byte to transfer + i2c_regs->cmd_status = I2C_CMD_RD; + else + i2c_regs->cmd_status = I2C_CMD_RD | I2C_CMD_NACK | I2C_CMD_STOP; + } + else if(i2c_dir == I2C_DIR_WRITE) { + //write a byte + //printf("\tWriting %x\n", *i2c_bufptr); + i2c_regs->data = *(i2c_bufptr++); + if(i2c_len > 1) + i2c_regs->cmd_status = I2C_CMD_WR; + else { + //printf("\tGenerating STOP\n"); + i2c_regs->cmd_status = I2C_CMD_WR | I2C_CMD_STOP; + } + }; + i2c_len--; + if(i2c_len == 0) i2c_state = I2C_STATE_LAST_BYTE; + else i2c_state = I2C_STATE_DATA; //takes care of the addr_sent->data transition + break; + + + case I2C_STATE_LAST_BYTE: //here we've already sent the last read request and the last data is waiting for us. + //printf("\tI2C in state LAST BYTE\n"); + + if(i2c_dir == I2C_DIR_READ) { + *(i2c_bufptr++) = i2c_regs->data; + //printf("\tRead %x\n", *(i2c_bufptr-1)); + i2c_state = I2C_STATE_DATA_READY; + } else { + i2c_state = I2C_STATE_IDLE; + } + i2c_regs->ctrl &= ~I2C_CTRL_IE; //disable interrupts until next time + + if(i2c_callback) { + i2c_callback(); //if we registered a callback, call it! + } + + break; + + + default: //terrible things have happened. + printf("you fail at life.\n"); + } + +} + +void i2c_register_callback(volatile void (*callback)(void)) { + i2c_callback = callback; +} + +inline void i2c_async_err(void) { + i2c_state = I2C_STATE_IDLE; + i2c_regs->ctrl &= ~I2C_CTRL_IE; + printf("I2C error\n"); +//TODO: set an error flag instead of just dropping things on the floor + i2c_regs->cmd_status = I2C_CMD_STOP; +} + +bool i2c_async_read(uint8_t addr, unsigned int len) { + //printf("Starting async read\n"); + if(i2c_state != I2C_STATE_IDLE) return false; //sorry mario but your i2c is in another castle + if(len == 0) return true; //just idiot-proofing + if(len > sizeof(i2c_buf)) return false; + + //disable I2C interrupts and clear pending interrupts on the I2C device + i2c_regs->ctrl &= ~I2C_CTRL_IE; + i2c_regs->cmd_status |= I2C_CMD_IACK; + + i2c_len = len; + i2c_dir = I2C_DIR_READ; + i2c_bufptr = i2c_buf; + //then set up the transfer by issuing the control byte + i2c_regs->ctrl |= I2C_CTRL_IE; + i2c_regs->data = (addr << 1) | 0x01; //7 bit addr and read bit + i2c_regs->cmd_status = I2C_CMD_WR | I2C_CMD_START; //generate start & start writing addr + //update the state so the irq handler knows what's going on + i2c_state = I2C_STATE_CONTROL_BYTE_SENT; + return true; +} + +bool i2c_async_write(uint8_t addr, const uint8_t *buf, unsigned int len) { + //printf("Starting async write\n"); + if(i2c_state != I2C_STATE_IDLE) return false; //sorry mario but your i2c is in another castle + if(len > sizeof(i2c_buf)) return false; + + //disable I2C interrupts and clear pending interrupts on the I2C device + i2c_regs->ctrl &= ~I2C_CTRL_IE; + i2c_regs->cmd_status |= I2C_CMD_IACK; + + //copy the buffer into our own if writing + memcpy(i2c_buf, buf, len); + + i2c_len = len; + i2c_dir = I2C_DIR_WRITE; + i2c_bufptr = i2c_buf; + //then set up the transfer by issuing the control byte + i2c_regs->ctrl |= I2C_CTRL_IE; + i2c_regs->data = (addr << 1) | 0x00; //7 bit addr and read bit + i2c_regs->cmd_status = I2C_CMD_WR | I2C_CMD_START; //generate start & start writing addr + //update the state so the irq handler knows what's going on + i2c_state = I2C_STATE_CONTROL_BYTE_SENT; + + return true; +} + +//TODO: determine if it's better to read sequentially into the user's buffer, copy on transfer complete, or copy on request (shown below). probably best to copy on request. +bool i2c_async_data_ready(const void *buf) { + if(i2c_state == I2C_STATE_DATA_READY) { + i2c_state = I2C_STATE_IDLE; + memcpy(buf, i2c_buf, (i2c_bufptr - i2c_buf)); //TODO: not really comfortable with this + //printf("Copying %d bytes to user buffer\n", i2c_bufptr-i2c_buf); + return true; + } + return false; +} + + diff --git a/firmware/microblaze/lib/i2c.h b/firmware/microblaze/lib/i2c.h index ecb6aa0d2..a991c6ac4 100644 --- a/firmware/microblaze/lib/i2c.h +++ b/firmware/microblaze/lib/i2c.h @@ -20,20 +20,38 @@ #define INCLUDED_I2C_H #include +#include "stdint.h" + +typedef enum { I2C_STATE_IDLE, + I2C_STATE_CONTROL_BYTE_SENT, + I2C_STATE_DATA, + I2C_STATE_LAST_BYTE, + I2C_STATE_DATA_READY, + I2C_STATE_ERROR + } i2c_state_t; + +typedef enum { I2C_DIR_WRITE=0, I2C_DIR_READ=1 } i2c_dir_t; void i2c_init(void); bool i2c_read (unsigned char i2c_addr, unsigned char *buf, unsigned int len); bool i2c_write(unsigned char i2c_addr, const unsigned char *buf, unsigned int len); +bool i2c_async_read(uint8_t addr, unsigned int len); +bool i2c_async_write(uint8_t addr, const uint8_t *buf, unsigned int len); +bool i2c_async_data_ready(const void *); +//static void i2c_irq_handler(unsigned irq); +void i2c_register_callback(void (*callback)(void)); // Write 24LC024 / 24LC025 EEPROM on motherboard or daughterboard. // Which EEPROM is determined by i2c_addr. See i2c_addr.h bool eeprom_write (int i2c_addr, int eeprom_offset, const void *buf, int len); +bool eeprom_write_async (int i2c_addr, int eeprom_offset, const void *buf, int len, void (*callback)(void)); // Read 24LC024 / 24LC025 EEPROM on motherboard or daughterboard. // Which EEPROM is determined by i2c_addr. See i2c_addr.h bool eeprom_read (int i2c_addr, int eeprom_offset, void *buf, int len); +bool eeprom_read_async(int i2c_addr, int eeprom_offset, void *buf, int len, void (*callback)(void)); #endif /* INCLUDED_I2C_H */ diff --git a/firmware/microblaze/lib/u2_init.c b/firmware/microblaze/lib/u2_init.c index 75bc40859..8d666b76b 100644 --- a/firmware/microblaze/lib/u2_init.c +++ b/firmware/microblaze/lib/u2_init.c @@ -45,22 +45,26 @@ get_hw_rev(void) bool u2_init(void) { + hal_disable_ints(); hal_io_init(); // init spi, so that we can switch over to the high-speed clock spi_init(); - // init i2c so we can read our rev - i2c_init(); - get_hw_rev(); - // set up the default clocks clocks_init(); + hal_uart_init(); + + // init i2c so we can read our rev pic_init(); // progammable interrupt controller + i2c_init(); + hal_enable_ints(); + get_hw_rev(); + bp_init(); // buffer pool - hal_enable_ints(); + // flash all leds to let us know board is alive hal_set_leds(0x0, 0x1f); -- cgit v1.2.3 From 579268112a8d17d527cd4f969346e20f7ce4321e Mon Sep 17 00:00:00 2001 From: Nick Foster Date: Tue, 10 Aug 2010 14:53:26 -0700 Subject: Bring in changes since last week. --- firmware/microblaze/apps/txrx_uhd.c | 28 ++++++++++------------------ 1 file changed, 10 insertions(+), 18 deletions(-) diff --git a/firmware/microblaze/apps/txrx_uhd.c b/firmware/microblaze/apps/txrx_uhd.c index 30c1a13b4..bdb793fd9 100644 --- a/firmware/microblaze/apps/txrx_uhd.c +++ b/firmware/microblaze/apps/txrx_uhd.c @@ -172,7 +172,7 @@ void handle_udp_data_packet( #define OTW_GPIO_BANK_TO_NUM(bank) \ (((bank) == USRP2_DIR_RX)? (GPIO_RX_BANK) : (GPIO_TX_BANK)) - //setup the output data +//setup the output data static usrp2_ctrl_data_t ctrl_data_out; static struct socket_address i2c_src, i2c_dst; @@ -190,7 +190,6 @@ void i2c_write_done_callback(void) { i2c_register_callback(0); } - void handle_udp_ctrl_packet( struct socket_address src, struct socket_address dst, unsigned char *payload, int payload_len @@ -200,9 +199,9 @@ void handle_udp_ctrl_packet( uint32_t ctrl_data_in_id = ctrl_data_in->id; //ensure that the protocol versions match - if (payload_len >= sizeof(uint32_t) && ctrl_data_in->proto_ver != USRP2_PROTO_VERSION){ - printf("!Error in control packet handler: Expected protocol version %d, but got %d\n", - USRP2_PROTO_VERSION, ctrl_data_in->proto_ver + if (payload_len >= sizeof(uint32_t) && ctrl_data_in->proto_ver != USRP2_FW_COMPAT_NUM){ + printf("!Error in control packet handler: Expected compatibility number %d, but got %d\n", + USRP2_FW_COMPAT_NUM, ctrl_data_in->proto_ver ); ctrl_data_in_id = USRP2_CTRL_ID_WAZZUP_BRO; } @@ -216,7 +215,7 @@ void handle_udp_ctrl_packet( } //setup the output data - ctrl_data_out.proto_ver = USRP2_PROTO_VERSION; + ctrl_data_out.proto_ver = USRP2_FW_COMPAT_NUM; ctrl_data_out.id=USRP2_CTRL_ID_HUH_WHAT; ctrl_data_out.seq=ctrl_data_in->seq; @@ -259,11 +258,6 @@ void handle_udp_ctrl_packet( case USRP2_CTRL_ID_DO_AN_I2C_READ_FOR_ME_BRO:{ uint8_t num_bytes = ctrl_data_in->data.i2c_args.bytes; i2c_register_callback(i2c_read_done_callback); - /*i2c_read( - ctrl_data_in->data.i2c_args.addr, - ctrl_data_out.data.i2c_args.data, - num_bytes - );*/ i2c_async_read( ctrl_data_in->data.i2c_args.addr, num_bytes @@ -273,12 +267,11 @@ void handle_udp_ctrl_packet( ctrl_data_out.id = USRP2_CTRL_ID_HERES_THE_I2C_DATA_DUDE; ctrl_data_out.data.i2c_args.bytes = num_bytes; } - //send_udp_pkt(USRP2_UDP_CTRL_PORT, src, &ctrl_data_out, sizeof(ctrl_data_out)); //TODO: NO break; case USRP2_CTRL_ID_WRITE_THESE_I2C_VALUES_BRO:{ uint8_t num_bytes = ctrl_data_in->data.i2c_args.bytes; - i2c_register_callback(i2c_write_done_callback); + i2c_register_callback(i2c_read_done_callback); i2c_async_write( ctrl_data_in->data.i2c_args.addr, ctrl_data_in->data.i2c_args.data, @@ -289,7 +282,6 @@ void handle_udp_ctrl_packet( ctrl_data_out.id = USRP2_CTRL_ID_COOL_IM_DONE_I2C_WRITE_DUDE; ctrl_data_out.data.i2c_args.bytes = num_bytes; } - //send_udp_pkt(USRP2_UDP_CTRL_PORT, src, &ctrl_data_out, sizeof(ctrl_data_out)); //TODO: NO break; /******************************************************************* @@ -347,9 +339,8 @@ void handle_udp_ctrl_packet( default: ctrl_data_out.id = USRP2_CTRL_ID_HUH_WHAT; send_udp_pkt(USRP2_UDP_CTRL_PORT, src, &ctrl_data_out, sizeof(ctrl_data_out)); - } - + } /* @@ -475,7 +466,8 @@ main(void) print_mac_addr(ethernet_mac_addr()->addr); newline(); print_ip_addr(get_ip_addr()); newline(); - printf("Control protocol version: %d\n", USRP2_PROTO_VERSION); + printf("FPGA compatibility number: %d\n", USRP2_FPGA_COMPAT_NUM); + printf("Firmware compatibility number: %d\n", USRP2_FW_COMPAT_NUM); ethernet_register_link_changed_callback(link_changed_callback); ethernet_init(); @@ -523,7 +515,7 @@ main(void) int pending = pic_regs->pending; // poll for under or overrun if (pending & PIC_UNDERRUN_INT){ - dbsm_handle_tx_underrun(&dsp_tx_sm); + //dbsm_handle_tx_underrun(&dsp_tx_sm); pic_regs->pending = PIC_UNDERRUN_INT; // clear interrupt putchar('U'); } -- cgit v1.2.3 From c4ae87f3554753877a35cab3b86cbf267fb2c035 Mon Sep 17 00:00:00 2001 From: Matt Ettus Date: Wed, 11 Aug 2010 18:58:04 -0700 Subject: rx error context packets should not be marked as errors in the fifo --- usrp2/vrt/vita_rx_framer.v | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/usrp2/vrt/vita_rx_framer.v b/usrp2/vrt/vita_rx_framer.v index fd82263d0..235817941 100644 --- a/usrp2/vrt/vita_rx_framer.v +++ b/usrp2/vrt/vita_rx_framer.v @@ -128,7 +128,7 @@ module vita_rx_framer VITA_ERR_SECS : pkt_fifo_line <= {2'b00,vita_time_fifo_o[63:32]}; VITA_ERR_TICS : pkt_fifo_line <= {2'b00,32'd0}; VITA_ERR_TICS2 : pkt_fifo_line <= {2'b00,vita_time_fifo_o[31:0]}; - VITA_ERR_PAYLOAD : pkt_fifo_line <= {2'b11,28'd0,flags_fifo_o}; + VITA_ERR_PAYLOAD : pkt_fifo_line <= {2'b10,28'd0,flags_fifo_o}; //VITA_ERR_TRAILER : pkt_fifo_line <= {2'b11,vita_trailer}; default : pkt_fifo_line <= 34'h0_FFFF_FFFF; -- cgit v1.2.3 From 1bee816db5a925b17577010542fbbc459722f481 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Wed, 11 Aug 2010 11:17:11 -0700 Subject: usrp: needed default constructor for MSVC, fixed gain group float warnings --- host/include/uhd/usrp/subdev_spec.hpp | 3 ++- host/test/gain_group_test.cpp | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/host/include/uhd/usrp/subdev_spec.hpp b/host/include/uhd/usrp/subdev_spec.hpp index 4d8f03b77..56aa0df20 100644 --- a/host/include/uhd/usrp/subdev_spec.hpp +++ b/host/include/uhd/usrp/subdev_spec.hpp @@ -40,7 +40,8 @@ namespace uhd{ namespace usrp{ * \param sd_name the name of a subdevice on that daughterboard */ subdev_spec_pair_t( - const std::string &db_name, const std::string &sd_name + const std::string &db_name = "", + const std::string &sd_name = "" ); }; diff --git a/host/test/gain_group_test.cpp b/host/test/gain_group_test.cpp index 6a6af8eb2..761372e5a 100644 --- a/host/test/gain_group_test.cpp +++ b/host/test/gain_group_test.cpp @@ -52,7 +52,7 @@ class gain_element2{ public: gain_range_t get_range(void){ - return gain_range_t(-20, 10, 0.1); + return gain_range_t(-20, 10, float(0.1)); } float get_value(void){ @@ -94,7 +94,7 @@ static gain_group::sptr get_gain_group(size_t pri1 = 0, size_t pri2 = 0){ /*********************************************************************** * Test cases **********************************************************************/ -static const double tolerance = 0.001; +static const float tolerance = float(0.001); BOOST_AUTO_TEST_CASE(test_gain_group_overall){ gain_group::sptr gg = get_gain_group(); -- cgit v1.2.3 From f29306c54536d0bbe9f76b67f4c3651888bc485e Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Thu, 12 Aug 2010 03:49:37 +0000 Subject: uhd: avoid segfaults - use CPP macros for paths and dont split empty string --- host/lib/constants.hpp.in | 7 ++++--- host/lib/utils/paths.cpp | 12 ++++++------ 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/host/lib/constants.hpp.in b/host/lib/constants.hpp.in index 295c8f16c..aa51e558c 100644 --- a/host/lib/constants.hpp.in +++ b/host/lib/constants.hpp.in @@ -21,8 +21,9 @@ #include #include -static const std::string UHD_VERSION_STRING = "@CPACK_PACKAGE_VERSION@"; -static const std::string UHD_INSTALL_PREFIX = "@CMAKE_INSTALL_PREFIX@"; -static const std::string UHD_PKG_DATA_DIR = "@PKG_DATA_DIR@"; +//these should be pre-processor macros to avoid static initialization issues +#define UHD_VERSION_STRING "@CPACK_PACKAGE_VERSION@" +#define UHD_INSTALL_PREFIX "@CMAKE_INSTALL_PREFIX@" +#define UHD_PKG_DATA_DIR "@PKG_DATA_DIR@" #endif /* INCLUDED_LIBUHD_CONSTANTS_HPP */ diff --git a/host/lib/utils/paths.cpp b/host/lib/utils/paths.cpp index 0805a44fe..4029bd989 100644 --- a/host/lib/utils/paths.cpp +++ b/host/lib/utils/paths.cpp @@ -60,12 +60,14 @@ static std::vector get_env_paths(const std::string &var_name){ //split the path at the path separators std::vector path_strings; - boost::split(path_strings, var_value, boost::is_any_of(env_path_sep)); + if (not var_value.empty()) boost::split(//dont split empty strings + path_strings, var_value, boost::is_any_of(env_path_sep) + ); //convert to filesystem path, filter blank paths std::vector paths; BOOST_FOREACH(std::string &path_string, path_strings){ - if (path_string.size() == 0) continue; + if (path_string.empty()) continue; paths.push_back(fs::system_complete(path_string)); } return paths; @@ -74,17 +76,15 @@ static std::vector get_env_paths(const std::string &var_name){ /*********************************************************************** * Get a list of special purpose paths **********************************************************************/ -static const fs::path pkg_data_path = fs::path(UHD_INSTALL_PREFIX) / UHD_PKG_DATA_DIR; - std::vector get_image_paths(void){ std::vector paths = get_env_paths("UHD_IMAGE_PATH"); - paths.push_back(pkg_data_path / "images"); + paths.push_back(fs::path(UHD_INSTALL_PREFIX) / UHD_PKG_DATA_DIR / "images"); return paths; } std::vector get_module_paths(void){ std::vector paths = get_env_paths("UHD_MODULE_PATH"); - paths.push_back(pkg_data_path / "modules"); + paths.push_back(fs::path(UHD_INSTALL_PREFIX) / UHD_PKG_DATA_DIR / "modules"); return paths; } -- cgit v1.2.3 From 38b6482e254c1b048bb724653d95f5630f92e279 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Thu, 12 Aug 2010 00:47:28 -0700 Subject: uhd: created floor_step to handle floating-point errors in gain group --- host/lib/utils/gain_group.cpp | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/host/lib/utils/gain_group.cpp b/host/lib/utils/gain_group.cpp index c113719c8..078fe56b2 100644 --- a/host/lib/utils/gain_group.cpp +++ b/host/lib/utils/gain_group.cpp @@ -35,6 +35,25 @@ static bool compare_by_step_size( return fcns.at(rhs).get_range().step > fcns.at(lhs).get_range().step; } +/*! + * Get a multiple of step with the following relation: + * result = step*floor(num/step) + * + * Due to small floating-point inaccuracies: + * num = n*step + e, where e is a small inaccuracy. + * When e is negative, floor would yeild (n-1)*step, + * despite that n*step is really the desired result. + * This function is designed to mitigate that issue. + * + * \param num the number to approximate + * \param step the step size to round with + * \param e the small inaccuracy to account for + * \return a multiple of step approximating num + */ +template static T floor_step(T num, T step, T e = T(0.001)){ + return step*int(num/step + e); +} + /*********************************************************************** * gain group implementation **********************************************************************/ @@ -82,9 +101,9 @@ public: float gain_left_to_distribute = gain; BOOST_FOREACH(const gain_fcns_t &fcns, all_fcns){ const gain_range_t range = fcns.get_range(); - gain_bucket.push_back( - max_step*int(std::clip(gain_left_to_distribute, range.min, range.max)/max_step) - ); + gain_bucket.push_back(floor_step(std::clip( + gain_left_to_distribute, range.min, range.max + ), max_step)); gain_left_to_distribute -= gain_bucket.back(); } @@ -106,9 +125,9 @@ public: //fill in the largest step sizes first that are less than the remainder BOOST_FOREACH(size_t i, indexes_step_size_dec){ const gain_range_t range = all_fcns.at(i).get_range(); - float additional_gain = range.step*int( - std::clip(gain_bucket.at(i) + gain_left_to_distribute, range.min, range.max - )/range.step) - gain_bucket.at(i); + float additional_gain = floor_step(std::clip( + gain_bucket.at(i) + gain_left_to_distribute, range.min, range.max + ), range.step) - gain_bucket.at(i); gain_bucket.at(i) += additional_gain; gain_left_to_distribute -= additional_gain; } -- cgit v1.2.3 From f89f7476a1c3452511d54ec6839f574a7a37c0fe Mon Sep 17 00:00:00 2001 From: Nick Foster Date: Tue, 10 Aug 2010 15:26:21 -0700 Subject: Brought in changes to SPI to match up with parallel branch so they share a common protocol. --- host/lib/usrp/usrp2/fw_common.h | 6 +++--- host/lib/usrp/usrp2/usrp2_iface.cpp | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/host/lib/usrp/usrp2/fw_common.h b/host/lib/usrp/usrp2/fw_common.h index a781c1a21..85d41d57f 100644 --- a/host/lib/usrp/usrp2/fw_common.h +++ b/host/lib/usrp/usrp2/fw_common.h @@ -104,12 +104,12 @@ typedef struct{ union{ __stdint(uint32_t) ip_addr; struct { - __stdint(uint8_t) dev; + __stdint(uint32_t) dev; + __stdint(uint32_t) data; __stdint(uint8_t) miso_edge; __stdint(uint8_t) mosi_edge; - __stdint(uint8_t) readback; - __stdint(uint32_t) data; __stdint(uint8_t) num_bits; + __stdint(uint8_t) readback; } spi_args; struct { __stdint(uint8_t) addr; diff --git a/host/lib/usrp/usrp2/usrp2_iface.cpp b/host/lib/usrp/usrp2/usrp2_iface.cpp index 4124221ef..2d450bfc6 100644 --- a/host/lib/usrp/usrp2/usrp2_iface.cpp +++ b/host/lib/usrp/usrp2/usrp2_iface.cpp @@ -115,7 +115,7 @@ public: //setup the out data usrp2_ctrl_data_t out_data; out_data.id = htonl(USRP2_CTRL_ID_TRANSACT_ME_SOME_SPI_BRO); - out_data.data.spi_args.dev = which_slave; + out_data.data.spi_args.dev = htonl(which_slave); out_data.data.spi_args.miso_edge = spi_edge_to_otw[config.miso_edge]; out_data.data.spi_args.mosi_edge = spi_edge_to_otw[config.mosi_edge]; out_data.data.spi_args.readback = (readback)? 1 : 0; -- cgit v1.2.3 From 936c5518e47f797c062c0ac5de0e5bd1452c7a0d Mon Sep 17 00:00:00 2001 From: Nick Foster Date: Wed, 11 Aug 2010 09:19:22 -0700 Subject: Fix warnings related to const-ness and volatile-ness. --- firmware/microblaze/lib/i2c.c | 12 ++++++------ firmware/microblaze/lib/i2c.h | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/firmware/microblaze/lib/i2c.c b/firmware/microblaze/lib/i2c.c index b60a05fcc..216b01800 100644 --- a/firmware/microblaze/lib/i2c.c +++ b/firmware/microblaze/lib/i2c.c @@ -39,12 +39,12 @@ static uint16_t prescaler_values[MAX_WB_DIV+1] = { //asynchronous (interrupt-driven) i2c state variables volatile uint8_t i2c_buf[17]; //tx/rx data transfer buffer -volatile uint8_t *i2c_bufptr = i2c_buf; //ptr to current position +volatile uint8_t *volatile i2c_bufptr = i2c_buf; //ptr to current position volatile uint8_t i2c_len = 0; //length remaining in current transfer volatile i2c_state_t i2c_state = I2C_STATE_IDLE; //current I2C transfer state i2c_dir_t i2c_dir; //I2C transfer direction -volatile void (*i2c_callback)(void); //function pointer to i2c callback to be called when transaction is complete +void (*volatile i2c_callback)(void); //function pointer to i2c callback to be called when transaction is complete static void i2c_irq_handler(unsigned irq); inline void i2c_async_err(void); @@ -228,7 +228,7 @@ static void i2c_irq_handler(unsigned irq) { } -void i2c_register_callback(volatile void (*callback)(void)) { +void i2c_register_callback(void (*volatile callback)(void)) { i2c_callback = callback; } @@ -272,7 +272,7 @@ bool i2c_async_write(uint8_t addr, const uint8_t *buf, unsigned int len) { i2c_regs->cmd_status |= I2C_CMD_IACK; //copy the buffer into our own if writing - memcpy(i2c_buf, buf, len); + memcpy((void *)i2c_buf, buf, len); i2c_len = len; i2c_dir = I2C_DIR_WRITE; @@ -288,10 +288,10 @@ bool i2c_async_write(uint8_t addr, const uint8_t *buf, unsigned int len) { } //TODO: determine if it's better to read sequentially into the user's buffer, copy on transfer complete, or copy on request (shown below). probably best to copy on request. -bool i2c_async_data_ready(const void *buf) { +bool i2c_async_data_ready(void *buf) { if(i2c_state == I2C_STATE_DATA_READY) { i2c_state = I2C_STATE_IDLE; - memcpy(buf, i2c_buf, (i2c_bufptr - i2c_buf)); //TODO: not really comfortable with this + memcpy(buf, (void *)i2c_buf, (i2c_bufptr - i2c_buf)); //TODO: not really comfortable with this //printf("Copying %d bytes to user buffer\n", i2c_bufptr-i2c_buf); return true; } diff --git a/firmware/microblaze/lib/i2c.h b/firmware/microblaze/lib/i2c.h index a991c6ac4..77129e922 100644 --- a/firmware/microblaze/lib/i2c.h +++ b/firmware/microblaze/lib/i2c.h @@ -38,7 +38,7 @@ bool i2c_write(unsigned char i2c_addr, const unsigned char *buf, unsigned int le bool i2c_async_read(uint8_t addr, unsigned int len); bool i2c_async_write(uint8_t addr, const uint8_t *buf, unsigned int len); -bool i2c_async_data_ready(const void *); +bool i2c_async_data_ready(void *); //static void i2c_irq_handler(unsigned irq); void i2c_register_callback(void (*callback)(void)); -- cgit v1.2.3 From c23a4c4334960b4c136e5cdb5b09556ea0d7c9a8 Mon Sep 17 00:00:00 2001 From: Nick Foster Date: Wed, 11 Aug 2010 15:43:47 -0700 Subject: Removed NACK checking so things don't barf when daughterboards aren't connected. When we have real error handling in the DUDE/BRO protocol we'll add this back in. --- firmware/microblaze/lib/i2c.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/firmware/microblaze/lib/i2c.c b/firmware/microblaze/lib/i2c.c index 216b01800..177341267 100644 --- a/firmware/microblaze/lib/i2c.c +++ b/firmware/microblaze/lib/i2c.c @@ -145,11 +145,12 @@ static void i2c_irq_handler(unsigned irq) { //printf("I2C irq handler\n"); //first let's make sure nothing is f'ed up - if(((i2c_regs->cmd_status & I2C_ST_RXACK) != 0) && i2c_dir == I2C_DIR_WRITE) { //we got a NACK and we didn't send it - printf("\tNACK received\n"); - i2c_async_err(); - return; - }// else printf("\tACK received, proceeding\n"); + //TODO: uncomment this error checking when we have some way to handle errors +// if(((i2c_regs->cmd_status & I2C_ST_RXACK) != 0) && i2c_dir == I2C_DIR_WRITE) { //we got a NACK and we didn't send it +// printf("\tNACK received\n"); +// i2c_async_err(); +// return; +// }// else printf("\tACK received, proceeding\n"); if(i2c_regs->cmd_status & I2C_ST_AL) { printf("\tArbitration lost!\n"); @@ -223,7 +224,7 @@ static void i2c_irq_handler(unsigned irq) { default: //terrible things have happened. - printf("you fail at life.\n"); + break; } } -- cgit v1.2.3 From 5b5f8901f5dfa179af3718a8a31001206a886ed3 Mon Sep 17 00:00:00 2001 From: Nick Foster Date: Wed, 11 Aug 2010 11:49:48 -0700 Subject: first stab at irq'ed spi --- firmware/microblaze/apps/txrx_uhd.c | 30 +++++++++++++++++++++------ firmware/microblaze/lib/spi.c | 41 +++++++++++++++++++++++++++++++++++++ firmware/microblaze/lib/spi.h | 7 +++++++ 3 files changed, 72 insertions(+), 6 deletions(-) diff --git a/firmware/microblaze/apps/txrx_uhd.c b/firmware/microblaze/apps/txrx_uhd.c index bdb793fd9..82e2e2b6f 100644 --- a/firmware/microblaze/apps/txrx_uhd.c +++ b/firmware/microblaze/apps/txrx_uhd.c @@ -174,7 +174,8 @@ void handle_udp_data_packet( //setup the output data static usrp2_ctrl_data_t ctrl_data_out; -static struct socket_address i2c_src, i2c_dst; +static struct socket_address i2c_src; +static struct socket_address spi_src; static volatile bool i2c_done = false; void i2c_read_done_callback(void) { @@ -190,6 +191,14 @@ void i2c_write_done_callback(void) { i2c_register_callback(0); } +static volatile bool spi_done = false; +static volatile uint32_t spi_readback_data; +void get_spi_readback_data(void) { + spi_readback_data = spi_get_data(); + spi_done = true; + spi_register_callback(0); +} + void handle_udp_ctrl_packet( struct socket_address src, struct socket_address dst, unsigned char *payload, int payload_len @@ -236,20 +245,24 @@ void handle_udp_ctrl_packet( ******************************************************************/ case USRP2_CTRL_ID_TRANSACT_ME_SOME_SPI_BRO:{ //transact - uint32_t result = spi_transact( - (ctrl_data_in->data.spi_args.readback == 0)? SPI_TXONLY : SPI_TXRX, + uint32_t result; + void (*volatile spicall)(void) = (ctrl_data_in->data.spi_args.readback == 0) ? 0 : get_spi_readback_data; //only need a callback if we're doing readback + bool success = spi_async_transact( + //(ctrl_data_in->data.spi_args.readback == 0)? SPI_TXONLY : SPI_TXRX, ctrl_data_in->data.spi_args.dev, //which device ctrl_data_in->data.spi_args.data, //32 bit data ctrl_data_in->data.spi_args.num_bits, //length in bits - (ctrl_data_in->data.spi_args.mosi_edge == USRP2_CLK_EDGE_RISE)? SPIF_PUSH_FALL : SPIF_PUSH_RISE | - (ctrl_data_in->data.spi_args.miso_edge == USRP2_CLK_EDGE_RISE)? SPIF_LATCH_RISE : SPIF_LATCH_FALL + (ctrl_data_in->data.spi_args.mosi_edge == USRP2_CLK_EDGE_RISE)? SPIF_PUSH_FALL : SPIF_PUSH_RISE | //flags + (ctrl_data_in->data.spi_args.miso_edge == USRP2_CLK_EDGE_RISE)? SPIF_LATCH_RISE : SPIF_LATCH_FALL, + spicall //callback ); //load output ctrl_data_out.data.spi_args.data = result; ctrl_data_out.id = USRP2_CTRL_ID_OMG_TRANSACTED_SPI_DUDE; + spi_src = src; } - send_udp_pkt(USRP2_UDP_CTRL_PORT, src, &ctrl_data_out, sizeof(ctrl_data_out)); +// send_udp_pkt(USRP2_UDP_CTRL_PORT, src, &ctrl_data_out, sizeof(ctrl_data_out)); break; /******************************************************************* @@ -512,6 +525,11 @@ main(void) //printf("Sending UDP packet from main loop for I2C...\n"); } + if(spi_done) { + spi_done = false; + send_udp_pkt(USRP2_UDP_CTRL_PORT, spi_src, &ctrl_data_out, sizeof(ctrl_data_out)); + } + int pending = pic_regs->pending; // poll for under or overrun if (pending & PIC_UNDERRUN_INT){ diff --git a/firmware/microblaze/lib/spi.c b/firmware/microblaze/lib/spi.c index bef808e57..4371b9b8a 100644 --- a/firmware/microblaze/lib/spi.c +++ b/firmware/microblaze/lib/spi.c @@ -17,6 +17,9 @@ #include "spi.h" #include "memory_map.h" +#include "nonstdio.h" + +void (*volatile spi_callback)(void); //SPI callback when xfer complete. void spi_init(void) @@ -59,3 +62,41 @@ spi_transact(bool readback, int slave, uint32_t data, int length, uint32_t flags else return 0; } + +void spi_register_callback(void (*volatile callback)(void)) { + spi_callback = callback; +} + +void spi_irq_handler(void) { + printf("SPI IRQ handler\n"); + if(spi_callback) spi_callback(); //we could just use the PIC to register the user's callback, but this provides the ability to do other things later +} + +uint32_t spi_get_data(void) { + return spi_regs->txrx0; +} + +bool +spi_async_transact(int slave, uint32_t data, int length, uint32_t flags, void (*volatile callback)(void)) { + flags &= (SPI_CTRL_TXNEG | SPI_CTRL_RXNEG); + int ctrl = SPI_CTRL_ASS | (SPI_CTRL_CHAR_LEN_MASK & length) | flags; + + if(spi_regs->ctrl & SPI_CTRL_GO_BSY) return false; //we don't wait on busy, we just return failure. + + // Tell it which SPI slave device to access + spi_regs->ss = slave & 0xffff; + + // Data we will send + spi_regs->txrx0 = data; + + // Run it -- write once and rewrite with GO set + spi_regs->ctrl = ctrl; + spi_regs->ctrl = ctrl | SPI_CTRL_GO_BSY; + + spi_regs->ctrl |= SPI_CTRL_IE; //we do these here so that we don't have to start the PIC before the SPI sets up the clocks on startup + pic_register_handler(IRQ_SPI, spi_irq_handler); + + spi_register_callback(callback); + + return true; +} diff --git a/firmware/microblaze/lib/spi.h b/firmware/microblaze/lib/spi.h index 01e4d26fd..18699f21a 100644 --- a/firmware/microblaze/lib/spi.h +++ b/firmware/microblaze/lib/spi.h @@ -48,6 +48,13 @@ void spi_wait(void); uint32_t spi_transact(bool readback, int slave, uint32_t data, int length, uint32_t flags); +bool +spi_async_transact(int slave, uint32_t data, int length, uint32_t flags, void (*volatile callback)(void)); + +uint32_t spi_get_data(void); +void spi_irq_handler(void); +void spi_register_callback(void (*volatile callback)(void)); + // ---------------------------------------------------------------- // Routines that manipulate the FLASH SPI BUS // ---------------------------------------------------------------- -- cgit v1.2.3 From 20d1f96f9594e299f8aef78cc70a587d1d87e289 Mon Sep 17 00:00:00 2001 From: Nick Foster Date: Wed, 11 Aug 2010 11:59:13 -0700 Subject: syntax --- firmware/microblaze/apps/txrx_uhd.c | 4 ++-- firmware/microblaze/lib/spi.c | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/firmware/microblaze/apps/txrx_uhd.c b/firmware/microblaze/apps/txrx_uhd.c index 82e2e2b6f..6fb01fec2 100644 --- a/firmware/microblaze/apps/txrx_uhd.c +++ b/firmware/microblaze/apps/txrx_uhd.c @@ -276,7 +276,7 @@ void handle_udp_ctrl_packet( num_bytes ); i2c_src = src; - i2c_dst = dst; +// i2c_dst = dst; ctrl_data_out.id = USRP2_CTRL_ID_HERES_THE_I2C_DATA_DUDE; ctrl_data_out.data.i2c_args.bytes = num_bytes; } @@ -291,7 +291,7 @@ void handle_udp_ctrl_packet( num_bytes ); i2c_src = src; - i2c_dst = dst; +// i2c_dst = dst; ctrl_data_out.id = USRP2_CTRL_ID_COOL_IM_DONE_I2C_WRITE_DUDE; ctrl_data_out.data.i2c_args.bytes = num_bytes; } diff --git a/firmware/microblaze/lib/spi.c b/firmware/microblaze/lib/spi.c index 4371b9b8a..33fcce05f 100644 --- a/firmware/microblaze/lib/spi.c +++ b/firmware/microblaze/lib/spi.c @@ -17,6 +17,7 @@ #include "spi.h" #include "memory_map.h" +#include "pic.h" #include "nonstdio.h" void (*volatile spi_callback)(void); //SPI callback when xfer complete. -- cgit v1.2.3 From ecc971c613d4a7dfe31bc142f99bfdba898d91eb Mon Sep 17 00:00:00 2001 From: Nick Foster Date: Wed, 11 Aug 2010 13:42:03 -0700 Subject: IRQ-based SPI works. Don't try to do multiple transactions without waiting for results first. In fact, don't try to do an I2C transaction while an SPI transaction is pending. --- firmware/microblaze/apps/txrx_uhd.c | 7 ++----- firmware/microblaze/lib/spi.c | 23 ++++++++++++++--------- firmware/microblaze/lib/spi.h | 8 ++++---- 3 files changed, 20 insertions(+), 18 deletions(-) diff --git a/firmware/microblaze/apps/txrx_uhd.c b/firmware/microblaze/apps/txrx_uhd.c index 6fb01fec2..1dd6e80ac 100644 --- a/firmware/microblaze/apps/txrx_uhd.c +++ b/firmware/microblaze/apps/txrx_uhd.c @@ -194,7 +194,7 @@ void i2c_write_done_callback(void) { static volatile bool spi_done = false; static volatile uint32_t spi_readback_data; void get_spi_readback_data(void) { - spi_readback_data = spi_get_data(); + ctrl_data_out.data.spi_args.data = spi_get_data(); spi_done = true; spi_register_callback(0); } @@ -245,8 +245,6 @@ void handle_udp_ctrl_packet( ******************************************************************/ case USRP2_CTRL_ID_TRANSACT_ME_SOME_SPI_BRO:{ //transact - uint32_t result; - void (*volatile spicall)(void) = (ctrl_data_in->data.spi_args.readback == 0) ? 0 : get_spi_readback_data; //only need a callback if we're doing readback bool success = spi_async_transact( //(ctrl_data_in->data.spi_args.readback == 0)? SPI_TXONLY : SPI_TXRX, ctrl_data_in->data.spi_args.dev, //which device @@ -254,11 +252,10 @@ void handle_udp_ctrl_packet( ctrl_data_in->data.spi_args.num_bits, //length in bits (ctrl_data_in->data.spi_args.mosi_edge == USRP2_CLK_EDGE_RISE)? SPIF_PUSH_FALL : SPIF_PUSH_RISE | //flags (ctrl_data_in->data.spi_args.miso_edge == USRP2_CLK_EDGE_RISE)? SPIF_LATCH_RISE : SPIF_LATCH_FALL, - spicall //callback + get_spi_readback_data //callback ); //load output - ctrl_data_out.data.spi_args.data = result; ctrl_data_out.id = USRP2_CTRL_ID_OMG_TRANSACTED_SPI_DUDE; spi_src = src; } diff --git a/firmware/microblaze/lib/spi.c b/firmware/microblaze/lib/spi.c index 33fcce05f..2a41a1bfa 100644 --- a/firmware/microblaze/lib/spi.c +++ b/firmware/microblaze/lib/spi.c @@ -22,6 +22,8 @@ void (*volatile spi_callback)(void); //SPI callback when xfer complete. +static void spi_irq_handler(unsigned irq); + void spi_init(void) { @@ -68,8 +70,10 @@ void spi_register_callback(void (*volatile callback)(void)) { spi_callback = callback; } -void spi_irq_handler(void) { - printf("SPI IRQ handler\n"); +static void spi_irq_handler(unsigned irq) { +// printf("SPI IRQ handler\n"); +// uint32_t wat = spi_regs->ctrl; //read a register just to clear the interrupt + //spi_regs->ctrl &= ~SPI_CTRL_IE; if(spi_callback) spi_callback(); //we could just use the PIC to register the user's callback, but this provides the ability to do other things later } @@ -80,9 +84,12 @@ uint32_t spi_get_data(void) { bool spi_async_transact(int slave, uint32_t data, int length, uint32_t flags, void (*volatile callback)(void)) { flags &= (SPI_CTRL_TXNEG | SPI_CTRL_RXNEG); - int ctrl = SPI_CTRL_ASS | (SPI_CTRL_CHAR_LEN_MASK & length) | flags; + int ctrl = SPI_CTRL_ASS | SPI_CTRL_IE | (SPI_CTRL_CHAR_LEN_MASK & length) | flags; - if(spi_regs->ctrl & SPI_CTRL_GO_BSY) return false; //we don't wait on busy, we just return failure. + if(spi_regs->ctrl & SPI_CTRL_GO_BSY) { + printf("Async SPI busy!\n"); + return false; //we don't wait on busy, we just return failure. we count on the host to not set up another transaction before the last one finishes. + } // Tell it which SPI slave device to access spi_regs->ss = slave & 0xffff; @@ -90,14 +97,12 @@ spi_async_transact(int slave, uint32_t data, int length, uint32_t flags, void (* // Data we will send spi_regs->txrx0 = data; + spi_register_callback(callback); + pic_register_handler(IRQ_SPI, spi_irq_handler); + // Run it -- write once and rewrite with GO set spi_regs->ctrl = ctrl; spi_regs->ctrl = ctrl | SPI_CTRL_GO_BSY; - spi_regs->ctrl |= SPI_CTRL_IE; //we do these here so that we don't have to start the PIC before the SPI sets up the clocks on startup - pic_register_handler(IRQ_SPI, spi_irq_handler); - - spi_register_callback(callback); - return true; } diff --git a/firmware/microblaze/lib/spi.h b/firmware/microblaze/lib/spi.h index 18699f21a..54618cedd 100644 --- a/firmware/microblaze/lib/spi.h +++ b/firmware/microblaze/lib/spi.h @@ -48,13 +48,13 @@ void spi_wait(void); uint32_t spi_transact(bool readback, int slave, uint32_t data, int length, uint32_t flags); -bool -spi_async_transact(int slave, uint32_t data, int length, uint32_t flags, void (*volatile callback)(void)); - uint32_t spi_get_data(void); -void spi_irq_handler(void); +//static void spi_irq_handler(unsigned irq); void spi_register_callback(void (*volatile callback)(void)); +bool +spi_async_transact(int slave, uint32_t data, int length, uint32_t flags, void (*volatile callback)(void)); + // ---------------------------------------------------------------- // Routines that manipulate the FLASH SPI BUS // ---------------------------------------------------------------- -- cgit v1.2.3 From 288f932423e96424fc4bb3b473c0247594e242e2 Mon Sep 17 00:00:00 2001 From: Nick Foster Date: Mon, 16 Aug 2010 17:44:05 -0700 Subject: usrp2: don't forward dbsm errors --- firmware/microblaze/lib/dbsm.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/firmware/microblaze/lib/dbsm.c b/firmware/microblaze/lib/dbsm.c index d495860fd..cee343eaa 100644 --- a/firmware/microblaze/lib/dbsm.c +++ b/firmware/microblaze/lib/dbsm.c @@ -160,12 +160,12 @@ dbsm_process_status(dbsm_t *sm, uint32_t status) putchar('E'); // Most likely an ethernet Rx error. We just restart the transfer. if (status & (BPS_ERROR(sm->buf0))) - //dbsm_error_helper(sm, sm->buf0); - dbsm_process_helper(sm, sm->buf0); //forward errors + dbsm_error_helper(sm, sm->buf0); + //dbsm_process_helper(sm, sm->buf0); //forward errors if (status & (BPS_ERROR(sm->buf0 ^ 1))) - //dbsm_error_helper(sm, sm->buf0 ^ 1); - dbsm_process_helper(sm, sm->buf0 ^ 1); //forward errors + dbsm_error_helper(sm, sm->buf0 ^ 1); + //dbsm_process_helper(sm, sm->buf0 ^ 1); //forward errors } if (status & BPS_DONE(sm->buf0)) -- cgit v1.2.3 From 230368da5c55c0eb587960db50f68e1b618f271c Mon Sep 17 00:00:00 2001 From: Nick Foster Date: Mon, 16 Aug 2010 18:21:37 -0700 Subject: Rev firmware compatibility number to 6 --- host/lib/usrp/usrp2/fw_common.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/host/lib/usrp/usrp2/fw_common.h b/host/lib/usrp/usrp2/fw_common.h index 85d41d57f..cc6c41ba7 100644 --- a/host/lib/usrp/usrp2/fw_common.h +++ b/host/lib/usrp/usrp2/fw_common.h @@ -34,7 +34,7 @@ extern "C" { //fpga and firmware compatibility numbers #define USRP2_FPGA_COMPAT_NUM 1 -#define USRP2_FW_COMPAT_NUM 5 +#define USRP2_FW_COMPAT_NUM 6 //used to differentiate control packets over data port #define USRP2_INVALID_VRT_HEADER 0 -- cgit v1.2.3 From 977651fd5710b1201b28b0cc4b6a9b0bd9871166 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Tue, 17 Aug 2010 11:05:28 -0700 Subject: uhd: add space to multiline string so quotes in the string cant disturb the multiline quotes --- host/config/Version.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/host/config/Version.cmake b/host/config/Version.cmake index a592a4565..9e4b6b306 100644 --- a/host/config/Version.cmake +++ b/host/config/Version.cmake @@ -42,7 +42,7 @@ ELSE(${GIT} STREQUAL "GIT-NOTFOUND") #extract the timestamp from the git log entry EXECUTE_PROCESS( WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} - COMMAND ${PYTHON_EXECUTABLE} -c "import re; print re.match('^.*Date:\\s*(\\d*).*$', '''${_git_log}''', re.MULTILINE | re.DOTALL).groups()[0]" + COMMAND ${PYTHON_EXECUTABLE} -c "import re; print re.match('^.*Date:\\s*(\\d*).*$', ''' ${_git_log} ''', re.MULTILINE | re.DOTALL).groups()[0]" OUTPUT_VARIABLE _git_timestamp OUTPUT_STRIP_TRAILING_WHITESPACE ) -- cgit v1.2.3 From 5f27d6edb43f74abd5c8a7bb10b0931b61c6218d Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Wed, 18 Aug 2010 12:24:15 -0700 Subject: uhd: windows path escape fix --- host/lib/CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/host/lib/CMakeLists.txt b/host/lib/CMakeLists.txt index cbb68c725..81845de21 100644 --- a/host/lib/CMakeLists.txt +++ b/host/lib/CMakeLists.txt @@ -54,11 +54,13 @@ INCLUDE(${CMAKE_CURRENT_SOURCE_DIR}/utils/CMakeLists.txt) # Append to the list of sources for lib uhd ######################################################################## FILE(TO_NATIVE_PATH ${CMAKE_INSTALL_PREFIX}/${PKG_DATA_DIR} LOCAL_PKG_DATA_DIR) +STRING(REPLACE "\\" "\\\\" LOCAL_PKG_DATA_DIR ${LOCAL_PKG_DATA_DIR}) MESSAGE(STATUS "Local package data directory: ${LOCAL_PKG_DATA_DIR}") IF(UNIX) #on unix systems, installers will use this directory for the package data FILE(TO_NATIVE_PATH /usr/${PKG_DATA_DIR} INSTALLER_PKG_DATA_DIR) + STRING(REPLACE "\\" "\\\\" INSTALLER_PKG_DATA_DIR ${INSTALLER_PKG_DATA_DIR}) MESSAGE(STATUS "Installer package data directory: ${INSTALLER_PKG_DATA_DIR}") ENDIF(UNIX) -- cgit v1.2.3 From 4aa48966bff52e5fec2980d27c762b82d3ff8f1e Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Wed, 18 Aug 2010 12:43:59 -0700 Subject: usrp2: template pick rate to avoid compile errors --- host/lib/usrp/usrp2/dsp_impl.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/host/lib/usrp/usrp2/dsp_impl.cpp b/host/lib/usrp/usrp2/dsp_impl.cpp index 347ec38af..6422142ce 100644 --- a/host/lib/usrp/usrp2/dsp_impl.cpp +++ b/host/lib/usrp/usrp2/dsp_impl.cpp @@ -31,9 +31,10 @@ static const size_t default_interp = 16; /*********************************************************************** * DDC Helper Methods **********************************************************************/ -static unsigned pick_closest_rate(double exact_rate, const std::vector &rates){ +template +static rate_type pick_closest_rate(double exact_rate, const std::vector &rates){ unsigned closest_match = rates.front(); - BOOST_FOREACH(unsigned possible_rate, rates){ + BOOST_FOREACH(rate_type possible_rate, rates){ if(std::abs(exact_rate - possible_rate) < std::abs(exact_rate - closest_match)) closest_match = possible_rate; } -- cgit v1.2.3 From 8740197dfed997bb235b73ec649edb803d544326 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Wed, 18 Aug 2010 13:42:47 -0700 Subject: uhd: docs on building and installing images --- host/docs/CMakeLists.txt | 1 + host/docs/images.rst | 104 +++++++++++++++++++++++++++++++++++++++++++++++ host/docs/index.rst | 1 + host/docs/usrp2.rst | 36 ---------------- 4 files changed, 106 insertions(+), 36 deletions(-) create mode 100644 host/docs/images.rst diff --git a/host/docs/CMakeLists.txt b/host/docs/CMakeLists.txt index d0041f71c..b4383f88d 100644 --- a/host/docs/CMakeLists.txt +++ b/host/docs/CMakeLists.txt @@ -24,6 +24,7 @@ SET(manual_sources coding.rst dboards.rst general.rst + images.rst usrp2.rst ) diff --git a/host/docs/images.rst b/host/docs/images.rst new file mode 100644 index 000000000..ff5c5404e --- /dev/null +++ b/host/docs/images.rst @@ -0,0 +1,104 @@ +======================================================================== +UHD - Firmware and FPGA Image Application Notes +======================================================================== + +.. contents:: Table of Contents + +------------------------------------------------------------------------ +Images Overview +------------------------------------------------------------------------ +Every USRP device must be loaded with special firmware and FPGA images. +The methods of loading images into the device varies among devices: + +* **USRP1:** The host code will automatically load the firmware and FPGA at runtime. +* **USRP2:** The user must manually write the images onto the USRP2 SD card. + +------------------------------------------------------------------------ +Pre-built images +------------------------------------------------------------------------ + +Pre-built images are available for download. +See the UHD wiki for the download link. + +The pre-built images come in platform-specific installer packages +and platform-independent archive files: + +* **Linux:** DEB or RPM installer +* **Windows:** not available yet... +* **Macintosh:** not available yet... +* **Platform-independent:** ZIP or TAR.GZ archive + +^^^^^^^^^^^^^^^^^^ +Linux installers +^^^^^^^^^^^^^^^^^^ +The Linux-based installers will install the images into /usr/share/uhd/images. +On a Linux system, the UHD will always search this path for image files. + +Commands to install a linux rpm or deb package: + +:: + + sudo rpm -i .rpm + + -- OR -- + + sudo dpkg -i .deb + +^^^^^^^^^^^^^^^^^^^^^^ +Archive install +^^^^^^^^^^^^^^^^^^^^^^ +When installing images from an archive, there are two options: + +**Option 1:** + +Unpack the archive into the UHD installation prefix. +The UHD will always search /share/uhd/images for image files. +Where was set by the CMAKE_INSTALL_PREFIX at configure-time. + +**Option 2:** + +Unpack the archive anywhere and set the UHD_IMAGE_PATH environment variable. +The UHD_IMAGE_PATH may contain a list of directories to search for image files, +or paths to specific image files. + +------------------------------------------------------------------------ +Building images +------------------------------------------------------------------------ + +The UHD source repository comes with the source code necessary to build +both firmware and FPGA images for all supported devices. +The build commands for a particular image can be found in /images/Makefile. + +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Xilinx FPGA builds +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Xilinx ISE 12.x and up is required to build the Xilinx FPGA images. +The build requires that you have a unix-like environment with make. +Make sure that xtclsh from the Xilinx ISE bin directory is in your $PATH. + +See /fpga/usrp2/top/* + +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Microblaze firmware builds +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +The Microblaze GCC compiler from the Xilinx EDK is required to build the Microblaze firmware images. +The build requires that you have a unix-like environment with autotools and make. +Make sure that mb-gcc from the Xilinx EDK/microblaze directory is in your $PATH. + +See /firmware/microblaze + +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Altera FPGA builds +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Quartus is required to build the Altera FPGA images. +Pre-built images can also be found in /fpga/usrp1/rbf + +See /fpga/usrp1/toplevel/* + +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +FX2 firmware builds +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +The sdcc compiler is required to build the FX2 firmware images. +The build requires that you have a unix-like environment with autotools and make. + +See /firmware/fx2 diff --git a/host/docs/index.rst b/host/docs/index.rst index b31a3d0ac..6973ede19 100644 --- a/host/docs/index.rst +++ b/host/docs/index.rst @@ -21,6 +21,7 @@ Building the UHD Application Notes ^^^^^^^^^^^^^^^^^^^^^ * `General App Notes <./general.html>`_ +* `Firmware and FPGA Image Notes <./images.html>`_ * `USRP2 App Notes <./usrp2.html>`_ * `Daughterboard App Notes <./dboards.html>`_ diff --git a/host/docs/usrp2.rst b/host/docs/usrp2.rst index bc4ea0e44..3ac326f58 100644 --- a/host/docs/usrp2.rst +++ b/host/docs/usrp2.rst @@ -4,42 +4,6 @@ UHD - USRP2 Application Notes .. contents:: Table of Contents ------------------------------------------------------------------------- -Building firmware and FPGA images ------------------------------------------------------------------------- - -^^^^^^^^^^^^^^^^^^ -FPGA Image -^^^^^^^^^^^^^^^^^^ -Xilinx ISE 10.1 and up is required to build the FPGA image for the USRP2. -The build requires that you have a unix-like environment with make. -Make sure that xtclsh from the Xilinx ISE bin directory is in your $PATH. - -Run the following commands: -:: - - cd /fpga/usrp2/top/u2_rev3 - make -f Makefile.udp bin - -*The image file will be ./build/u2_rev3.bin* - -^^^^^^^^^^^^^^^^^^ -Firmware Image -^^^^^^^^^^^^^^^^^^ -The Microblaze GCC compiler from the Xilinx EDK is required to build the firmware. -The build requires that you have a unix-like environment with autotools and make. -Make sure that mb-gcc from the Xilinx EDK/microblaze directory is in your $PATH. - -Run the following commands: -:: - - cd /firmware/microblaze - ./boostrap - ./configure --host=mb - make - -*The image file will be ./usrp2/usrp2_txrx_uhd.bin* - ------------------------------------------------------------------------ Load the images onto the SD card ------------------------------------------------------------------------ -- cgit v1.2.3 From afb22c9d15ab5cfa4b843942f656d9eb978587f7 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Wed, 18 Aug 2010 17:33:09 -0700 Subject: usrp: rethrow validate subdev spec errors with additional info --- host/lib/usrp/misc_utils.cpp | 65 ++++++++++++++++++++++++-------------------- 1 file changed, 36 insertions(+), 29 deletions(-) diff --git a/host/lib/usrp/misc_utils.cpp b/host/lib/usrp/misc_utils.cpp index 46094ba32..a1664d810 100644 --- a/host/lib/usrp/misc_utils.cpp +++ b/host/lib/usrp/misc_utils.cpp @@ -25,6 +25,7 @@ #include #include #include +#include using namespace uhd; using namespace uhd::usrp; @@ -132,43 +133,49 @@ static void verify_xx_subdev_spec( wax::obj mboard, std::string xx_type ){ - prop_names_t dboard_names = mboard[dboard_names_prop].as(); - UHD_ASSERT_THROW(dboard_names.size() > 0); //well i hope there is a dboard + try{ + prop_names_t dboard_names = mboard[dboard_names_prop].as(); + UHD_ASSERT_THROW(dboard_names.size() > 0); //well i hope there is a dboard - //the subdevice specification is empty: handle automatic - if (subdev_spec.empty()){ - BOOST_FOREACH(const std::string &db_name, dboard_names){ - wax::obj dboard = mboard[named_prop_t(dboard_prop, db_name)]; + //the subdevice specification is empty: handle automatic + if (subdev_spec.empty()){ + BOOST_FOREACH(const std::string &db_name, dboard_names){ + wax::obj dboard = mboard[named_prop_t(dboard_prop, db_name)]; + + //if the dboard slot is populated, take the first subdevice + if (dboard[DBOARD_PROP_DBOARD_ID].as() != dboard_id_t::none()){ + std::string sd_name = dboard[DBOARD_PROP_SUBDEV_NAMES].as().front(); + subdev_spec.push_back(subdev_spec_pair_t(db_name, sd_name)); + break; + } + } - //if the dboard slot is populated, take the first subdevice - if (dboard[DBOARD_PROP_DBOARD_ID].as() != dboard_id_t::none()){ + //didnt find any populated dboards: add the first subdevice + if (subdev_spec.empty()){ + std::string db_name = dboard_names.front(); + wax::obj dboard = mboard[named_prop_t(dboard_prop, db_name)]; std::string sd_name = dboard[DBOARD_PROP_SUBDEV_NAMES].as().front(); subdev_spec.push_back(subdev_spec_pair_t(db_name, sd_name)); - break; } } - //didnt find any populated dboards: add the first subdevice - if (subdev_spec.empty()){ - std::string db_name = dboard_names.front(); - wax::obj dboard = mboard[named_prop_t(dboard_prop, db_name)]; - std::string sd_name = dboard[DBOARD_PROP_SUBDEV_NAMES].as().front(); - subdev_spec.push_back(subdev_spec_pair_t(db_name, sd_name)); - } - } - - //sanity check that the dboard/subdevice names exist for this mboard - BOOST_FOREACH(const subdev_spec_pair_t &pair, subdev_spec){ - //empty db name means select dboard automatically - if (pair.db_name.empty()){ - if (dboard_names.size() != 1) throw std::runtime_error( - "A daughterboard name must be provided for multi-slot boards: " + subdev_spec.to_string() - ); - pair.db_name == dboard_names.front(); + //sanity check that the dboard/subdevice names exist for this mboard + BOOST_FOREACH(const subdev_spec_pair_t &pair, subdev_spec){ + //empty db name means select dboard automatically + if (pair.db_name.empty()){ + if (dboard_names.size() != 1) throw std::runtime_error( + "A daughterboard name must be provided for multi-slot boards: " + subdev_spec.to_string() + ); + pair.db_name == dboard_names.front(); + } + uhd::assert_has(dboard_names, pair.db_name, xx_type + " dboard name"); + wax::obj dboard = mboard[named_prop_t(dboard_prop, pair.db_name)]; + uhd::assert_has(dboard[DBOARD_PROP_SUBDEV_NAMES].as(), pair.sd_name, xx_type + " subdev name"); } - uhd::assert_has(dboard_names, pair.db_name, xx_type + " dboard name"); - wax::obj dboard = mboard[named_prop_t(dboard_prop, pair.db_name)]; - uhd::assert_has(dboard[DBOARD_PROP_SUBDEV_NAMES].as(), pair.sd_name, xx_type + " subdev name"); + }catch(const std::exception &e){ + throw std::runtime_error(str(boost::format( + "Validate %s subdev spec failed: %s\n %s" + ) % xx_type % subdev_spec.to_string() % e.what())); } } -- cgit v1.2.3 From b84f2da152eb65afe89240941bd02d67b3582eae Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Thu, 19 Aug 2010 13:33:31 -0700 Subject: uhd: replaced tx continuous app with tx waveform app (siggen example app) --- host/examples/CMakeLists.txt | 8 +- host/examples/tx_continuous_samples.cpp | 110 ------------------------ host/examples/tx_waveforms.cpp | 144 ++++++++++++++++++++++++++++++++ 3 files changed, 148 insertions(+), 114 deletions(-) delete mode 100644 host/examples/tx_continuous_samples.cpp create mode 100644 host/examples/tx_waveforms.cpp diff --git a/host/examples/CMakeLists.txt b/host/examples/CMakeLists.txt index 10a9a833a..c3bbbcd04 100644 --- a/host/examples/CMakeLists.txt +++ b/host/examples/CMakeLists.txt @@ -16,9 +16,6 @@ # -ADD_EXECUTABLE(tx_continuous_samples tx_continuous_samples.cpp) -TARGET_LINK_LIBRARIES(tx_continuous_samples uhd) - ADD_EXECUTABLE(benchmark_rx_rate benchmark_rx_rate.cpp) TARGET_LINK_LIBRARIES(benchmark_rx_rate uhd) @@ -28,10 +25,13 @@ TARGET_LINK_LIBRARIES(rx_timed_samples uhd) ADD_EXECUTABLE(tx_timed_samples tx_timed_samples.cpp) TARGET_LINK_LIBRARIES(tx_timed_samples uhd) +ADD_EXECUTABLE(tx_waveforms tx_waveforms.cpp) +TARGET_LINK_LIBRARIES(tx_waveforms uhd) + INSTALL(TARGETS - tx_continuous_samples benchmark_rx_rate rx_timed_samples tx_timed_samples + tx_waveforms RUNTIME DESTINATION ${PKG_DATA_DIR}/examples ) diff --git a/host/examples/tx_continuous_samples.cpp b/host/examples/tx_continuous_samples.cpp deleted file mode 100644 index cf70b07fb..000000000 --- a/host/examples/tx_continuous_samples.cpp +++ /dev/null @@ -1,110 +0,0 @@ -// -// Copyright 2010 Ettus Research LLC -// -// This program 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 -// (at your option) any later version. -// -// This program 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 this program. If not, see . -// - -#include -#include -#include -#include -#include //system time -#include -#include -#include - -namespace po = boost::program_options; - -int UHD_SAFE_MAIN(int argc, char *argv[]){ - uhd::set_thread_priority_safe(); - - //variables to be set by po - std::string args; - size_t total_duration; - size_t samps_per_packet; - double tx_rate, freq; - float ampl; - - //setup the program options - po::options_description desc("Allowed options"); - desc.add_options() - ("help", "help message") - ("args", po::value(&args)->default_value(""), "simple uhd device address args") - ("duration", po::value(&total_duration)->default_value(3), "number of seconds to transmit") - ("spp", po::value(&samps_per_packet)->default_value(1000), "number of samples per packet") - ("txrate", po::value(&tx_rate)->default_value(100e6/16), "rate of outgoing samples") - ("freq", po::value(&freq)->default_value(0), "rf center frequency in Hz") - ("ampl", po::value(&l)->default_value(float(0.3)), "amplitude of each sample") - ("dilv", "specify to disable inner-loop verbose") - ; - po::variables_map vm; - po::store(po::parse_command_line(argc, argv, desc), vm); - po::notify(vm); - - //print the help message - if (vm.count("help")){ - std::cout << boost::format("UHD TX Continuous Samples %s") % desc << std::endl; - return ~0; - } - - bool verbose = vm.count("dilv") == 0; - - //create a usrp device - std::cout << std::endl; - std::cout << boost::format("Creating the usrp device with: %s...") % args << std::endl; - uhd::usrp::simple_usrp::sptr sdev = uhd::usrp::simple_usrp::make(args); - uhd::device::sptr dev = sdev->get_device(); - std::cout << boost::format("Using Device: %s") % sdev->get_pp_string() << std::endl; - - //set properties on the device - std::cout << boost::format("Setting TX Rate: %f Msps...") % (tx_rate/1e6) << std::endl; - sdev->set_tx_rate(tx_rate); - std::cout << boost::format("Actual TX Rate: %f Msps...") % (sdev->get_tx_rate()/1e6) << std::endl; - sdev->set_tx_freq(freq); - - //allocate data to send - std::vector > buff(samps_per_packet, std::complex(ampl, ampl)); - - //setup the metadata flags - uhd::tx_metadata_t md; - md.start_of_burst = true; //always SOB (good for continuous streaming) - md.end_of_burst = false; - - //send the data in multiple packets - boost::system_time end_time(boost::get_system_time() + boost::posix_time::seconds(total_duration)); - while(end_time > boost::get_system_time()){ - //send samples per packet (driver fragments internally) - size_t num_tx_samps = dev->send( - &buff.front(), samps_per_packet, md, - uhd::io_type_t::COMPLEX_FLOAT32, - uhd::device::SEND_MODE_FULL_BUFF - ); - if(verbose) std::cout << std::endl << boost::format("Sent %d samples") % num_tx_samps << std::endl; - } - - //send a mini EOB packet - if(verbose) std::cout << std::endl << boost::format("Sending packet with end-of-burst") << std::endl; - md.start_of_burst = false; - md.end_of_burst = true; - dev->send( - NULL, 0, md, - uhd::io_type_t::COMPLEX_FLOAT32, - uhd::device::SEND_MODE_FULL_BUFF - ); - - //finished - std::cout << std::endl << "Done!" << std::endl << std::endl; - - return 0; -} diff --git a/host/examples/tx_waveforms.cpp b/host/examples/tx_waveforms.cpp new file mode 100644 index 000000000..e9cf210bb --- /dev/null +++ b/host/examples/tx_waveforms.cpp @@ -0,0 +1,144 @@ +// +// Copyright 2010 Ettus Research LLC +// +// This program 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 +// (at your option) any later version. +// +// This program 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 this program. If not, see . +// + +#include +#include +#include +#include +#include //system time +#include +#include +#include +#include + +namespace po = boost::program_options; + +int UHD_SAFE_MAIN(int argc, char *argv[]){ + uhd::set_thread_priority_safe(); + + //variables to be set by po + std::string args, wave_type; + size_t total_duration, amspb; + double rate, freq, wave_freq; + float ampl, gain; + + //setup the program options + po::options_description desc("Allowed options"); + desc.add_options() + ("help", "help message") + ("args", po::value(&args)->default_value(""), "simple uhd device address args") + ("duration", po::value(&total_duration)->default_value(3), "number of seconds to transmit") + ("amspb", po::value(&amspb)->default_value(10000), "approximate mimimum samples per buffer") + ("rate", po::value(&rate)->default_value(100e6/16), "rate of outgoing samples") + ("freq", po::value(&freq)->default_value(0), "rf center frequency in Hz") + ("ampl", po::value(&l)->default_value(float(0.3)), "amplitude of the waveform") + ("gain", po::value(&gain)->default_value(float(0)), "gain for the RF chain") + ("wave-type", po::value(&wave_type)->default_value("SINE"), "waveform type (CONST, SQUARE, RAMP, SINE)") + ("wave-freq", po::value(&wave_freq)->default_value(0), "waveform frequency in Hz") + ; + po::variables_map vm; + po::store(po::parse_command_line(argc, argv, desc), vm); + po::notify(vm); + + //print the help message + if (vm.count("help")){ + std::cout << boost::format("UHD TX Waveforms %s") % desc << std::endl; + return ~0; + } + + //create a usrp device + std::cout << std::endl; + std::cout << boost::format("Creating the usrp device with: %s...") % args << std::endl; + uhd::usrp::simple_usrp::sptr sdev = uhd::usrp::simple_usrp::make(args); + uhd::device::sptr dev = sdev->get_device(); + std::cout << boost::format("Using Device: %s") % sdev->get_pp_string() << std::endl; + + //set the tx sample rate + std::cout << boost::format("Setting TX Rate: %f Msps...") % (rate/1e6) << std::endl; + sdev->set_tx_rate(rate); + std::cout << boost::format("Actual TX Rate: %f Msps...") % (sdev->get_tx_rate()/1e6) << std::endl << std::endl; + + //set the tx center frequency + std::cout << boost::format("Setting TX Freq: %f Mhz...") % (freq/1e6) << std::endl; + sdev->set_tx_freq(freq); + std::cout << boost::format("Actual TX Freq: %f Mhz...") % (sdev->get_tx_freq()/1e6) << std::endl << std::endl; + + //set the tx rf gain + std::cout << boost::format("Setting TX Gain: %f dB...") % gain << std::endl; + sdev->set_tx_gain(gain); + std::cout << boost::format("Actual TX Gain: %f dB...") % sdev->get_tx_gain() << std::endl << std::endl; + + //for the const wave, set the wave freq for small samples per period + if (wave_freq == 0 and wave_type == "CONST"){ + wave_freq = sdev->get_tx_rate()/2; + } + + //error when the waveform is not possible to generate + if (std::abs(wave_freq)/sdev->get_tx_rate() < 0.5/amspb){ + throw std::runtime_error("wave freq/tx rate too small"); + } + if (std::abs(wave_freq) > sdev->get_tx_rate()/2){ + throw std::runtime_error("wave freq out of Nyquist zone"); + } + + //fill a buffer with one period worth of samples + std::vector period(size_t(sdev->get_tx_rate()/std::abs(wave_freq))); + std::cout << boost::format("Samples per waveform period: %d") % period.size() << std::endl; + for (size_t n = 0; n < period.size(); n++){ + if (wave_type == "CONST") period[n] = ampl; + else if (wave_type == "SQUARE") period[n] = (n > period.size()/2)? ampl : 0; + else if (wave_type == "RAMP") period[n] = float((n/double(period.size()-1)) * 2*ampl - ampl); + else if (wave_type == "SINE") period[n] = ampl*float(std::sin(2*M_PI*n/double(period.size()))); + else throw std::runtime_error("unknown waveform type: " + wave_type); + } + + //allocate data to send (fill with several periods worth of IQ samples) + const size_t periods_per_buff = std::max(1, amspb/period.size()); + std::vector > buff(period.size()*periods_per_buff); + std::cout << boost::format("Samples per send buffer: %d") % buff.size() << std::endl; + const size_t i_ahead = (wave_freq > 0)? period.size()/4 : 0; + const size_t q_ahead = (wave_freq < 0)? period.size()/4 : 0; + for (size_t n = 0; n < buff.size(); n++) buff[n] = std::complex( + period[(n+i_ahead)%period.size()], period[(n+q_ahead)%period.size()] //I,Q + ); + + //setup the metadata flags + uhd::tx_metadata_t md; + md.start_of_burst = true; //always SOB (good for continuous streaming) + md.end_of_burst = false; + + //send the data in multiple packets + boost::system_time end_time(boost::get_system_time() + boost::posix_time::seconds(total_duration)); + while(end_time > boost::get_system_time()) dev->send( + &buff.front(), buff.size(), md, + uhd::io_type_t::COMPLEX_FLOAT32, + uhd::device::SEND_MODE_FULL_BUFF + ); + + //send a mini EOB packet + md.start_of_burst = false; + md.end_of_burst = true; + dev->send(NULL, 0, md, + uhd::io_type_t::COMPLEX_FLOAT32, + uhd::device::SEND_MODE_FULL_BUFF + ); + + //finished + std::cout << std::endl << "Done!" << std::endl << std::endl; + + return 0; +} -- cgit v1.2.3