/* * fw_app.c * * Copyright (C) 2019 Sylvain Munaut * All rights reserved. * * LGPL v3+, see LICENSE.lgpl3 * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #include "console.h" #include "led.h" #include "mini-printf.h" #include "spi.h" #include "utils.h" #include "registers.h" #include "generation.h" /* FLASH */ #define FLASH_MAILBOX_STORAGE 0x0F0000 static uint32_t copy_array[16]; /* double dupa; float kupa; */ /* Local generation params for tweaking actual HW generation params */ static tweaked_params_union_s out_params; /* Local copy of last button register values */ static button_regs_t last_button_regs; /* Disabled as the clock constraints won't accept it static inline uint32_t rdcycle(void) { uint32_t cycle; __asm__ volatile ("rdcycle %0" : "=r" (cycle)); return cycle; } */ static inline uint32_t my_rdcycle(void) { volatile uint32_t *timer_reg = (void*)TIMER_BASE; return *timer_reg; } /* Timer fuction */ #define CYCLES_DIV 24000000.0f #define UPDATE_S 0.1f #define DEBUG_PRINT_S 3.0f // TODO: integers not floats? static uint32_t last_rdcycle; static uint32_t last_rdcycle_debug; static bool timer_expired(uint32_t * last_rdcycle, float timeout) { bool success = false; uint32_t current = my_rdcycle(); uint32_t diff = current - *last_rdcycle; float elapsed_seconds = (float)(diff) / CYCLES_DIV; if (elapsed_seconds > timeout) { //printf("Timeout expired rdcycle: %d last %d\n", current, *last_rdcycle); *last_rdcycle = current; success = true; } return success; } static void write_regs_to_mailbox() { mailbox_regs->regs.period1 = 9900; //out_params.regs._period1; // TODO: seems like period2 etc are missing mailbox_regs->regs.delay1 = 4000; //out_params.regs._duty1; mailbox_regs->regs.period2 = 9000; //out_params.regs._period2; mailbox_regs->regs.delay2 = 3000; //out_params.regs._duty2; mailbox_regs->regs.period3 = 100; mailbox_regs->regs.duty3 = 50; //mailbox_regs->regs.delay3 = out_params.regs.D3 / FXP_SCALING; mailbox_regs->regs.npuls3 = 5; //out_params.regs.N3; mailbox_regs->regs.odd_train_flag = N_PULSE_TRAINS; // TODO: is this proper? } static void print_mailbox_contents() { int i = 0; printf("Mailbox contents:\n"); for(i = 0; i < 16; ++i) printf("Mailbox[%d]: %d\n", i, mailbox_regs->data[i]); } static void print_kbrd(const button_deltas_t *pDeltas) { //printf("f1 : %d\n", pDeltas->inc_f1 ); //printf("d1 : %d\n", pDeltas->inc_d1 ); //printf("d2 : %d\n", pDeltas->inc_d2 ); //printf("ph2: %d\n", pDeltas->inc_ph2); //printf("ph3: %d\n", pDeltas->inc_ph3); //printf("f3 : %d\n", pDeltas->inc_f3 ); //printf("d3 : %d\n", pDeltas->inc_d3 ); //printf("n3 : %d\n", pDeltas->inc_n3 ); printf("mailbox_button_regs: 0x%08x\n", mailbox_button_regs); for(int i=0;i<16;i++){ printf("butt[%d]=%d\n", i, mailbox_button_regs->data[i]); } } static void print_params(tweaked_params_s *pParams) { printf("User params:\n"); printf("f1: %d\n", pParams->f1); printf("_period1: %d\n", pParams->_period1); printf("D1: %d\n", pParams->D1); printf("_duty1: %d\n", pParams->_duty1); printf("D2: %d\n", pParams->D2); printf("_duty2: %d\n", pParams->_duty2); printf("Ph2: %d\n", pParams->Ph2); printf("_phase2: %d\n", pParams->_phase2); printf("Ph3: %d\n", pParams->Ph3); printf("f3: %d\n", pParams->f3); printf("_period3: %d\n", pParams->_period3); printf("D3: %d\n", pParams->D3); printf("N3: %d\n", pParams->N3); printf("ena: %d\n", pParams->ena); } static void read_generation_values_from_flash() { flash_read((void*)copy_array, FLASH_MAILBOX_STORAGE, sizeof(copy_array)); // Copy data to actual registers for (int i = 0; i < 14; ++i) out_params.data[i] = copy_array[i]; } static void store_generation_values_flash() { printf("store_generation_values_flash()\n"); printf("WARNING - IMPLEMENTATION DISABLED\n"); // // TODO: can we remove it already as we don't read directly to mailbox // // Copy current mailbox array to a temporary array for bulk memory write // // our Wishbone implementation does not support bulk writes // for (int i = 0; i < 14; ++i) // copy_array[i] = out_params.data[i]; // // flash_write_enable(); // flash_sector_erase(FLASH_MAILBOX_STORAGE); // // Wait for flash to finish (poll status register) // while (flash_read_sr() & 0x01) /* WIP bit */; // flash_write_enable(); // // flash_page_program((void*)copy_array, FLASH_MAILBOX_STORAGE, sizeof(copy_array)); // while (flash_read_sr() & 0x01) /* WIP bit */; } static void serial_no_init() { uint8_t buf[8]; flash_manuf_id(buf); printf("Flash Manufacturer : %s\n", hexstr(buf, 3, true)); flash_unique_id(buf); printf("Flash Unique ID : %s\n", hexstr(buf, 8, true)); //dummy_write_to_flash(); /* Testing floats TODO: test if calculation is correct dupa = 3.1415; kupa = 2.74f; dupa *= kupa; printf("Pi * e: %.3f\n", dupa); */ } static void print_flash_contents() { read_generation_values_from_flash(); print_mailbox_contents(); } static void boot_dfu(void) { /* Boot firmware */ volatile uint32_t *boot = (void*)0x80000000; *boot = (1 << 2) | (1 << 0); } void usb_dfu_rt_cb_reboot(void) { boot_dfu(); } void main() { int cmd = 0; /* Init console IO */ console_init(); puts("Booting App image..\n"); /* SPI */ spi_init(); /* Enable USB directly */ serial_no_init(); /* Read generation reg values from flash */ read_generation_values_from_flash(); /* If values are wrong - fill defaults */ if (validate_generation_values(&out_params.regs) != 0) init_params(&out_params.regs); write_regs_to_mailbox(); /* Main loop */ while (1) { /* Run the timer for button updates periodically */ if (timer_expired(&last_rdcycle, UPDATE_S)) { button_deltas_t button_deltas = {}; obtain_button_deltas(mailbox_button_regs, &last_button_regs, &button_deltas); print_kbrd(&button_deltas); // button registers only show the delta between last and current value - we don't reset them explicitly update_three_signal_values(&out_params.regs, &button_deltas); write_regs_to_mailbox(); // TODO: how do we use this? clarify! if (mailbox_regs->regs.write_flash) { store_generation_values_flash(); mailbox_regs->regs.write_flash = 0x0; } } /* Debug timer */ if (timer_expired(&last_rdcycle_debug, DEBUG_PRINT_S)) { // Print user params print_params(&out_params.regs); } #ifdef USE_KEYBOARD /* Prompt ? */ if (cmd >= 0) printf("Command> "); /* Poll for command */ cmd = getchar_nowait(); if (cmd >= 0) { if (cmd > 32 && cmd < 127) { putchar(cmd); putchar('\r'); putchar('\n'); } switch (cmd) { case '.': printf("Current rdcycle %d\n", my_rdcycle()); break; case '/': boot_dfu(); break; case 's': inc_D1(&out_params.regs, 1); break; case 'x': dec_D1(&out_params.regs, 1); break; case 'd': inc_D2(&out_params.regs, 1); break; case 'c': dec_D2(&out_params.regs, 1); break; case 'f': inc_f1(&out_params.regs, 1); break; case 'v': dec_f1(&out_params.regs, 1); break; case 'a': inc_Ph2(&out_params.regs, 1); break; case 'z': dec_Ph2(&out_params.regs, 1); break; case 'g': inc_f3(&out_params.regs, 1); break; case 'b': dec_f3(&out_params.regs, 1); break; case 'k': inc_Ph3(&out_params.regs, 1); break; case ',': dec_Ph3(&out_params.regs, 1); break; case 'j': inc_D3(&out_params.regs, 1); break; case 'm': dec_D3(&out_params.regs, 1); break; case 'h': inc_N3(&out_params.regs, 1); break; case 'n': dec_N3(&out_params.regs, 1); break; case 'e': ena_force_toggle(&out_params.regs); break; case ']': print_flash_contents(); break; default: break; } } #endif } }