-
Main.h
11/17/2020 at 16:12 • 0 comments#ifndef MAIN_H_ #define MAIN_H_ // Serial port stuff #include <string.h> #include <stdio.h> // Printing a string to the serial port void print_serial(const char * const print_string); // Given an input array, process the command void go_process_command(); #endif // MAIN_H_
-
ATMEGA256RFR2 project code
11/02/2020 at 03:47 • 0 commentsHere is the code for the microcontroller (ATMEGA256RFR2, running at 3.3 V)
#include <avr/io.h> // LOW.CLKDIV8 is unchecked, and LOW.CKSEL_SUT is Transceiver Oscillator; Start-up time: 16K CK + 65 ms #define F_CPU 16000000UL #include <util/delay.h> #include <avr/interrupt.h> #include "main.h" // Place to store a string for USART communication static char temp_string[64]; // Simple routine to output a serial string to the UART void print_serial(const char * const print_string) { uint8_t temp = 0; while (temp < strlen(print_string)) { if ((UCSR1A & 0x20) == 0) { // Do nothing _delay_us(10); } else { // Send a byte UDR1 = (uint8_t) print_string[temp]; temp = temp + 1; } } // Send ASCII 13 and 10 temp = 0; while (temp < 2) { if ((UCSR1A & 0x20) == 0) { // Do nothing _delay_us(10); } else { if (temp == 0) { UDR1 = 13; } if (temp == 1) { UDR1 = 10; } temp = temp + 1; } } } // Place to store the user input static uint8_t rx_in_buffer[64]; // The count of user input static uint8_t rx_in_buffer_count = 0; ISR(USART1_RX_vect) { // Read the character from the buffer uint8_t temp = UDR1; // Put the character in the buffer rx_in_buffer[rx_in_buffer_count] = temp; // Increment the count rx_in_buffer_count = rx_in_buffer_count + 1; // Count has to be less than 63 if (rx_in_buffer_count > 63) { rx_in_buffer_count = 63; } // If the character is carriage return, process the command if (temp == 13) { go_process_command(); } } void go_process_command() { // Print some characters in the buffer //snprintf(temp_string, 64, "Rx: %d, %d, %d, %d, %d, %d", rx_in_buffer[0], rx_in_buffer[1], rx_in_buffer[2], rx_in_buffer[3], rx_in_buffer[4], rx_in_buffer[5]); //print_serial(temp_string); // The read command if ((rx_in_buffer[0] == 114) || (rx_in_buffer[0] == 82)) { // The read command, r or R, expect decimal, for example, expect r72 to read 0x48, OCR0B //print_serial("r/R"); // The location of the carriage return uint8_t ind_13 = 0; // Find character 13 for (uint8_t ii = 1; ii < 64; ii++) { if (rx_in_buffer[ii] == 13) { ind_13 = ii; break; } } // Where character 13 was found //snprintf(temp_string, 64, "Char13: %d", ind_13); //print_serial(temp_string); // For processing the register address (convert ASCII characters to addr) uint8_t found_it = 0; uint16_t addr = 0; uint16_t pow_10 = 1; // If ind_13 was found, build up addr if (ind_13 > 1) { for (uint8_t ii = (ind_13 - 1); ii > 0; ii--) { if ((rx_in_buffer[ii] >= 48) || (rx_in_buffer[ii] <= 57)) { addr = addr + (rx_in_buffer[ii] - 48) * pow_10; pow_10 = pow_10 * 10; found_it = 1; } else { // Unexpected character found_it = 0; break; } } } // Print the address and whether the parsing was as expected //snprintf(temp_string, 64, "addr: %u, found_it: %d", addr, found_it); //print_serial(temp_string); // Print the register value if (found_it == 1) { volatile uint8_t * reg_addr = (uint8_t *) addr; uint8_t temp_value = *reg_addr; snprintf(temp_string, 64, "Reg: %u = %d, %x", addr, temp_value, temp_value); print_serial(temp_string); } } else if ((rx_in_buffer[0] == 119) || (rx_in_buffer[0] == 87)) { // The write command, w or W, for example, expect w72=4 //print_serial("w/W"); // The location of the carriage return uint8_t ind_13 = 0; // Find character 13, carriage return for (uint8_t ii = 1; ii < 64; ii++) { if (rx_in_buffer[ii] == 13) { ind_13 = ii; break; } } // The location of the = uint8_t ind_eq = 0; for (uint8_t ii = 1; ii < 64; ii++) { if (rx_in_buffer[ii] == 61) { ind_eq = ii; break; } } // Where character = and 13 were found //snprintf(temp_string, 64, "Char=: %d, 13: %d", ind_eq, ind_13); //print_serial(temp_string); if ((ind_eq > 1) && ((ind_eq + 1) < ind_13)) { // For processing the register address (convert ASCII characters to addr) uint8_t found_it = 0; uint16_t addr = 0; uint16_t pow_10 = 1; // Get the register address for (uint8_t ii = (ind_eq - 1); ii > 0; ii--) { if ((rx_in_buffer[ii] >= 48) || (rx_in_buffer[ii] <= 57)) { addr = addr + (rx_in_buffer[ii] - 48) * pow_10; pow_10 = pow_10 * 10; found_it = 1; } else { // Unexpected character found_it = 0; break; } } // Print the address and whether the parsing was as expected //snprintf(temp_string, 64, "addr: %u, found_it: %d", addr, found_it); //print_serial(temp_string); // Attempt to set the register value if (found_it == 1) { // Print the current value of the register volatile uint8_t * reg_addr = (uint8_t *) addr; //snprintf(temp_string, 64, "Reg: %u = %d, old value", addr, *reg_addr); //print_serial(temp_string); // Now, parse the value found_it = 0; pow_10 = 1; uint16_t in_val = 0; // Get the value for (uint8_t ii = (ind_13 - 1); ii > ind_eq; ii--) { if ((rx_in_buffer[ii] >= 48) || (rx_in_buffer[ii] <= 57)) { in_val = in_val + (rx_in_buffer[ii] - 48) * pow_10; pow_10 = pow_10 * 10; found_it = 1; } else { // Unexpected character found_it = 0; break; } } // Print the value and whether the parsing was as expected //snprintf(temp_string, 64, "New value: %d, found_it: %d", in_val, found_it); //print_serial(temp_string); if ((found_it == 1) && (in_val <= 255)) { // Write the value *reg_addr = (uint8_t) in_val; snprintf(temp_string, 64, "Reg: %u = %d, new value", addr, in_val); print_serial(temp_string); } } } } else { print_serial("Command error"); } // Last things to do // Set the buffer count to 0 rx_in_buffer_count = 0; // Clear the buffer for (uint8_t ii = 0; ii < 64; ii++) { rx_in_buffer[ii] = 0; } } int main(void) { // Get the UART ready UBRR1H = 0; // Oscillator is 16 MHz, 9600 is decimal 103 UBRR1L = 103; // Enable Rx interrupt, enable Rx, enable Tx UCSR1B = (1 << 7) | (1 << 4) | (1 << 3); // Enable RXCIE1, Enable Tx and Rx UCSR1C = (0 << 6) | (0 << 4) | (0 << 3) | (3 << 1); // Asynchronous, No parity, 8 bits _delay_ms(1); // Enable interrupts SREG |= (1 << 7); // PB4 is the USER_LED, labeled LED0 on the ATMEGA256RFR2 xplained board DDRB = (1 << 4); // PG0 is for chip select DDRG = 1; PORTG = 1; // Use USART0 as SPI UBRR0L = 0; // Set to 0 first UBRR0H = 0; DDRE = (1 << 2); // Set XCK0 to output // UDORD0 - MSB first, UCPHA0 , UCPOL0 UCSR0C = (3 << 6) | (0 << 2) | (0 << 1) | (0); // Enable Rx and Tx UCSR0B = (1 << 4) | (1 << 3); // Now set the baud rate UBRR0L = 3; // Target 2 Mbps (assuming 16 MHz CPU clock) UBRR0H = 0; _delay_ms(1); // Echo to the user to start print_serial("Go time!"); while (1) { // Blink the LED while waiting for the interrupt PORTB |= (1 << 4); _delay_ms(500); PORTB &= 255 - (1 << 4); _delay_ms(500); } }
Here is the header file
#ifndef MAIN_H_ #define MAIN_H_ // Serial port stuff #include <string.h> #include <stdio.h> // Printing a string to the serial port void print_serial(const char * const print_string); // Given an input array, process the command void go_process_command(); #endif // MAIN_H_
-
Code for the FPGA
10/30/2020 at 18:01 • 0 commentsHere is the code for the FPGA. I noted the pin numbers in at the top...
// Main module - monitor the ports from the microcontroller module spi_micro_test( input wire clk, // 50 MHz clock, pin 27 input wire bar_ss, // SPI chip select, pin 93 input wire mosi, // SPI master output, pin 92 input wire sck, // SPI clock, pin 99 output wire miso, // SPI sidekick output, pin 101 output wire led1, // LED1 pin 132 output wire led2, // LED2 pin 134 output wire led3, // LED3 pin 135 output wire led4, // LED4 pin 140 output wire led5); // LED5 pin 141 ////// // Observe the serial clock reg [2:0] sck_r; initial begin sck_r <= 3'b000; end always @ (posedge clk) begin sck_r <= {sck_r[1:0], sck}; end // Detect the rising edge wire sck_risingedge = (sck_r[2:1]==2'b01); // Detect the falling edge wire sck_fallingedge = (sck_r[2:1]==2'b10); ////// // Observe the mosi wire reg [1:0] mosi_r; always @ (posedge clk) begin mosi_r <= {mosi_r[0], mosi}; end // The mosi data wire mosi_data = mosi_r[1]; ////// // Observe bar_ss reg[2:0] bar_ss_r; initial begin bar_ss_r <= 3'b111; end always @ (posedge clk) begin bar_ss_r <= {bar_ss_r[1:0], bar_ss}; end // Detect the rising edge // wire bar_ss_risingedge = (bar_ss_r[2:1]==2'b01); // Detect the falling edge wire bar_ss_fallingedge = (bar_ss_r[2:1]==2'b10); // Observation of bar_ss wire bar_ss_observe = bar_ss_r[1]; ////// // Place to store input data // reg data_ready; reg [2:0] bit_count; reg [7:0] data_rx; ////// // Place to store the output data reg [7:0] data_tx; initial begin data_tx <= 8'b01100101; end // Output is tristate, until bar_ss_observe becomes 0 assign miso = (!bar_ss_observe) ? data_tx[7] : 1'bz; // Capture the value of the bar_ss input from the microcontroller always @(posedge clk) begin if (bar_ss_fallingedge == 1'b1) begin // On the falling edge of bar_ss, clear data ready // data_ready <= 1'b0; bit_count <= 3'b000; end else if ((bar_ss_observe == 1'b0) && (sck_risingedge == 1'b1)) begin // If bar_ss is low and on the rising edge, bring in a bit bit_count <= bit_count + 3'b001; data_rx <= {data_rx[6:0], mosi_data}; end else if ((bar_ss_observe == 1'b0) && (sck_fallingedge == 1'b1)) begin data_tx <= {data_tx[6:0], data_tx[7]}; end end // Set the LED outputs assign led1 = data_rx[0]; assign led2 = data_rx[1]; assign led3 = data_rx[2]; assign led4 = data_rx[3]; assign led5 = bar_ss_observe; endmodule