| // Apollo SPI interface - | |
| // (C) 2011 Phil Harman VK6APH, Dave McQuate WA8YWQ | |
| // | |
| // HPSDR - High Performance Software Defined Radio | |
| // | |
| // Hermes code. | |
| // | |
| // 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 2 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, write to the Free Software | |
| // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
| /* | |
| Apollo Reset | |
| SCLK +------------------------------------------------------------------------------------------------+ | |
| +----+ | |
| Reset ------------+ +---------------------------+ | |
| +------------------------------------------------------------+ | |
| < --------------------------5 mS ----------------------------> | |
| Protocol - set Frequency | |
| SCLK +--+ +--+ +--+ +--+ +--+ +--+ +--+ +--+ +--+ +--+ +--+ +--+ +--+ +--+ +--+ +--+ +--+ +--+ +--+ +--+ +--+ +--+ +--+ +--+ +--+ +--+ +--+ | |
| -------+ +--+ +--+ +--+ +--+ +--+ +--+ +--+ +--+ +--+ +--+ +--+ +--+ +--+ +--+ +--+ +--+ + --+ +--+ +--+ +--+ +--+ +--+ +--+ +--+ +--+ +--+ +-- | |
| <15kHz> | |
| Enable ----+ +--- | |
| +-------------------------------------------------------------------------------------------------------- --------------------------------------------------------------+ | |
| STATUS --+ +--- | |
| +---------------------------------------------------------------------------------------------------------- -------------------------------------------------------------+ | |
| MOSI --------+----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+ +-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+ | |
| | 1 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | X | | X | X | X | X | X | X | X | X | X | X | | |
| --------+----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+ +-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+ | |
| <--------------- Sync Byte 0x88 --------------> <---------------- Message ID (0x01) ----------> <--------------------------- frequency -------------------------------> | |
| */ | |
| // This module provides the communication between Hermes and Apollo | |
| // Dave McQuate WA8YWQ | |
| // January 4, 2011 | |
| // 4 July 2012 - sync byte changed from 0x80 to 0x88 by Espen to match previous USB version | |
| // 6 Jan 2013 - modified PTT timer code. Removed ATU commands since not yet implemented in Apollo uP code. Phil Harman VK6APH | |
| // - removed read of Apollo status since not yet implemented in Apollo uP code. VK6APH | |
| // To do: | |
| // Additional capabilities to be added: | |
| // status query | |
| // version query | |
| // tuner settings query | |
| module Apollo (reset, clock, frequency, timeout, PTT, Filter, Tuner, ANT_TUNE, | |
| SPI_SDI, SPI_SDO, SPI_SCK, ApolloStatusLine, ApolloReset, ApolloEnable, statusAvailable, status, FilterSelect); | |
| input reset; // do nothing while reset is high; reset Apollo for 5ms when reset drops low | |
| input clock; // 30 kHz | |
| input [31:0] frequency; | |
| input [15:0] timeout; | |
| input PTT; // enable PA bias | |
| input Filter; // enable filter bank | |
| input Tuner; // enable antenna tuner | |
| input ANT_TUNE; // start tuning cycle | |
| input SPI_SDI; // receive serial data from Apollo | |
| output SPI_SDO; // send serial data, MOSI, to Apollo | |
| output SPI_SCK; // serial data clock, SCLK, nominally 15 kHz | |
| input ApolloStatusLine; // Apollo sets it low when it wants to send data to Hermes | |
| output ApolloReset; // reset Apollo uC (active low) | |
| output ApolloEnable; | |
| output statusAvailable; // Flag set when status bytes have been received from Apollo | |
| output [87:0] status; // Status info returned by Apollo after it receives a message | |
| input FilterSelect; // high => use Alex, low => use Apollo | |
| reg SPI_SDO; | |
| reg SPI_SCK; | |
| reg ApolloReset = 1'b1; | |
| reg ApolloEnable = 1'b1; | |
| reg statusAvailable; | |
| reg [87:0] status; | |
| parameter ClockFrequency = 30000; | |
| localparam resetCount = ClockFrequency * 5 / 1000; // At 30kHz clock freq, 150 clocks = 5 ms | |
| //localparam resetCount = 7'd10; // #### smaller value for simulation | |
| reg [7:0] resetCounter; | |
| reg [31:0] lastFrequency; | |
| reg lastPTT; | |
| reg lastFilter; | |
| reg lastTuner; | |
| reg lastTuneStart; | |
| reg [4:0] state; | |
| reg [4:0] count; // count both rising & falling edges of SPI_SCK for 16 data bits | |
| reg [15:0] message; // simple commands: left byte = 8'h88, right byte = message ID | |
| reg [7:0] statusCount; // count edges of SPI_SCK while reading status bytes from Apollo | |
| reg [4:0] msCount; // This counter and timeoutCount together | |
| reg [15:0] timeoutCount; // are used to extend PTT enable when input PTT remains high | |
| reg renewPTT; | |
| // values for state: | |
| localparam RESET = 5'd0, | |
| RESET_APOLLO = 5'd1, | |
| INIT = 5'd2, | |
| WAIT = 5'd3, | |
| SIMPLE_MESSAGE = 5'd4, | |
| RECEIVE_STATUS = 5'd5, | |
| SET_FREQUENCY = 5'd6, // send sync & message_id | |
| LOAD_FREQ1 = 5'd7, // load freq word 1 | |
| SEND_FREQ1 = 5'd8, // send freq word 1 | |
| LOAD_FREQ2 = 5'd9, // load freq word 2 | |
| SEND_FREQ2 = 5'd10, // send freq word 2 | |
| GET_FREQ_STATUS = 5'd11, // get status after frequency setting | |
| ENABLE_PTT = 5'd12, // send sync & message_id | |
| LOAD_TIMEOUT = 5'd13, // load timeout value | |
| SEND_TIMEOUT = 5'd14, // send timeout value | |
| PTT_STATUS = 5'd15, // get status after enabling PTT | |
| READ_STATUS = 5'd16, | |
| Alex = 5'd31; // Apollo not present: don't touch SPI lines | |
| // Nominal clock frequency is 30 kHz. PTT timeout is is milliseconds. | |
| // As long as PTT continues to be high, we need to send additional | |
| // enable PTT message before Apollo's PTT timeout expires. | |
| // These enable PTT message should be sent before the timeout expires, | |
| // but not too frequently. | |
| always @ (posedge clock) | |
| begin | |
| if (reset) begin | |
| state <= RESET; | |
| renewPTT <= 0; | |
| timeoutCount <= 0; | |
| end | |
| // else if (FilterSelect) state <= Alex; // if FilterSelect is high, Apollo is not present | |
| else if (PTT) begin | |
| if (timeoutCount >= 16'd6000) begin // 6000 renews PTT approx every 250mS with 30kHz clock. | |
| renewPTT <= 1; // set flag indicating we need to renew enable PTT | |
| end | |
| else timeoutCount <= timeoutCount + 1'b1; | |
| end | |
| case(state) | |
| Alex: begin | |
| end | |
| RESET: begin | |
| ApolloReset <= 1'b1; | |
| ApolloEnable <= 1'b1; | |
| SPI_SCK <= 1; // Hold SPI clock high | |
| resetCounter <= 0; | |
| if (!reset) state <= RESET_APOLLO; | |
| end | |
| RESET_APOLLO: begin | |
| ApolloReset <= 0; // reset Apollo uP | |
| SPI_SCK <= 1; // keeping SPI clock high #### do I need this??? | |
| if (resetCounter == resetCount) state <= INIT; | |
| resetCounter <= resetCounter + 1'b1; | |
| end | |
| INIT: begin | |
| ApolloReset <= 1'b1; // end of Apollo uP reset | |
| ApolloEnable <= 1'b1; // active low | |
| lastFrequency <= frequency; // set initial state... | |
| lastPTT <= 0; | |
| lastFilter <= 0; | |
| lastTuner <= 0; | |
| lastTuneStart <= 0; | |
| state <= WAIT; | |
| end | |
| WAIT: begin | |
| SPI_SCK <= 0; // SPI clock to idle state | |
| ApolloEnable <= 1'b1; // set to inactive | |
| count <= 0; | |
| if (frequency != lastFrequency) begin // might want to exclude a few low bits in the comparison??? | |
| message <= 16'h8801; // If frequency changed, send new value | |
| state <= SET_FREQUENCY; | |
| ApolloEnable <= 1'b0; | |
| lastFrequency <= frequency; | |
| end | |
| else if ( (PTT != lastPTT) || renewPTT ) begin // send enable PTT message | |
| if (renewPTT) begin | |
| timeoutCount <= 0; | |
| renewPTT <= 0; | |
| end | |
| if (PTT) begin | |
| message <= 16'h8802; // enable PTT has timeout parameter | |
| state <= ENABLE_PTT; | |
| end | |
| else begin | |
| message <= 16'h8803; // disable PTT has NO parameter | |
| state <= SIMPLE_MESSAGE; | |
| end | |
| ApolloEnable <= 1'b0; | |
| lastPTT <= PTT; | |
| end | |
| // else if (Filter != lastFilter) begin // If there's a change, send filter enable or disable message | |
| // lastFilter <= Filter; | |
| // if (Filter) message <= 16'h8804; | |
| // else message <= 16'h8805; | |
| // state <= SIMPLE_MESSAGE; | |
| // ApolloEnable <= 1'b0; | |
| // lastFilter <= Filter; | |
| // end | |
| // else if (Tuner != lastTuner) begin // If there's a change, send tuner enable or disable message | |
| // lastTuner <= Tuner; | |
| // if (Tuner) message <= 16'h8806; | |
| // else message <= 16'h8807; | |
| // state <= SIMPLE_MESSAGE; | |
| // ApolloEnable <= 1'b0; | |
| // lastTuner <= Tuner; | |
| // end | |
| // else if (ANT_TUNE != lastTuneStart) begin // when requested, begin auto-tuning | |
| // lastTuneStart <= ANT_TUNE; | |
| // if (ANT_TUNE) message <= 16'h8808; // start tuning cycle | |
| // else message <= 16'h8809; // abort tuning cycle | |
| // state <= SIMPLE_MESSAGE; | |
| // ApolloEnable <= 1'b0; | |
| // lastTuneStart <= ANT_TUNE; | |
| // end | |
| else state <= WAIT; | |
| end | |
| // all commands to Apollo begin with h88 sync byte + message ID byte | |
| // This section sends the 16 bit value in message out on SPI_SDO, high bit first. | |
| // First, the 16 bit value is a sync byte and a message ID. | |
| // Thereafter it might be the high or low word of the frequency, or the value of timeout. | |
| // When done, this section increments state. | |
| // Before entering, set count to zero. SPI_SCK is low (idle). | |
| // After exiting, SPI_SCK should be set low. | |
| SIMPLE_MESSAGE, SET_FREQUENCY, ENABLE_PTT, SEND_FREQ1, SEND_FREQ2, SEND_TIMEOUT: begin | |
| if (!count[0]) begin // on even counts, but new bit onto SPI_SDO | |
| SPI_SDO <= message[15]; | |
| SPI_SCK <= 0; // and set clock low | |
| state <= state; | |
| end | |
| else begin | |
| SPI_SCK <= 1; | |
| message <= {message[14:0], 1'b0}; | |
| if (count == 5'd31) begin | |
| state <= state + 1'b1; // still need to set SPI_SCK low | |
| count <= 0; | |
| end | |
| else state <= state; | |
| end | |
| count <= count + 1'b1; | |
| end | |
| // send current frequency, low byte first | |
| LOAD_FREQ1: begin | |
| SPI_SCK <= 0; | |
| message <= { frequency[7:0], frequency[15:8] }; | |
| state <= SEND_FREQ1; | |
| end | |
| LOAD_FREQ2: begin | |
| SPI_SCK <= 0; | |
| message <= { frequency[23:16], frequency[31:24] }; | |
| state <= SEND_FREQ2; | |
| end | |
| // send timeout value (in ms), low byte first | |
| LOAD_TIMEOUT: begin | |
| SPI_SCK <= 0; | |
| message <= { timeout[7:0], timeout[15:8] }; | |
| state <= SEND_TIMEOUT; | |
| end | |
| // "Normal" status returned from Apollo is -- | |
| // frequency uint32 | |
| // PTT status byte | |
| // PTT timeout uint16 | |
| // LPF status byte | |
| // ATO status byte | |
| // "Version" data returned -- | |
| // protocol byte | |
| // firmware rev byte, byte, byte | |
| // hardware rev byte | |
| RECEIVE_STATUS, GET_FREQ_STATUS, PTT_STATUS: // now don't need to retain separate sequences of states | |
| begin | |
| SPI_SCK <= 0; // return SPI clock to idle state | |
| state <= WAIT; | |
| // if (ApolloStatusLine == 1'b0) begin // wait for ApolloStatus line to go low | |
| // statusCount <= 0; // final count 8'd144; | |
| // state <= WAIT; | |
| ///* -----\/----- EXCLUDED -----\/----- | |
| // state <= READ_STATUS; | |
| // -----/\----- EXCLUDED -----/\----- */ | |
| // end | |
| // else state <= state; | |
| end | |
| // For each bit to be read from Apollo, set SPI_SCK high. | |
| // Read the value sent while setting SPI_SCK low. | |
| //READ_STATUS: | |
| //begin | |
| // if (statusCount[0] == 1'b0) begin | |
| // SPI_SCK <= 1'b1; | |
| // end | |
| // else begin | |
| // SPI_SCK <= 1'b0; | |
| // status <= { status[86:0], SPI_SDI }; // read SPI_SDI when setting SPI_SCK low; repeat for 88 bits; store all in single buffer | |
| // if (statusCount == 8'd177) begin // test value = number of bits * 2 + 1 (value must be odd) | |
| // statusAvailable <= 1'b1; | |
| // state <= WAIT; // all done; wait for next change | |
| // end | |
| // end | |
| // statusCount <= statusCount + 1'b1; | |
| //end | |
| default: state <= RESET; | |
| endcase | |
| end | |
| /* SIMPLE_MESSAGE SEND TIMING DIAGRAM | |
| clock rising edges | |
| | | | | | | | | | | | | | | | | | | | | | |
| count 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 ... | |
| SDO x m15 m14 m13 m12 m11 m10 m9 m8 ... | |
| SCK 0 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 | |
| */ | |
| /* | |
| Note: | |
| Default (i.e. at power up) filter bank and antenna tuner are both disabled | |
| */ | |
| endmodule | |
Xet Storage Details
- Size:
- 12.9 kB
- Xet hash:
- 964e9a0396b621c3756cb2bda64f1061fbc2658a6fede8bc6853ac059863193e
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.